Skip to content

Commit

Permalink
refactor: Recorder and the examples.
Browse files Browse the repository at this point in the history
  • Loading branch information
nkaz001 committed May 19, 2024
1 parent e740463 commit 849775c
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 33 deletions.
15 changes: 4 additions & 11 deletions rust/examples/algo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use std::{collections::HashMap, fmt::Debug};
use hftbacktest::prelude::*;
use tracing::info;

pub fn gridtrading<Q, MD, I: Interface<Q, MD>>(
pub fn gridtrading<Q, MD, I, R>(
hbt: &mut I,
recorder: &mut R,
half_spread: f64,
grid_interval: f64,
skew: f64,
Expand All @@ -13,13 +14,13 @@ pub fn gridtrading<Q, MD, I: Interface<Q, MD>>(
where
Q: Sized + Clone,
MD: MarketDepth,
I: Interface<Q, MD>,
<I as Interface<Q, MD>>::Error: Debug,
R: Recorder,
{
let grid_num = 20;
let max_position = grid_num as f64 * order_qty;

let tick_size = hbt.depth(0).tick_size() as f64;
let price_prec = get_precision(tick_size as f32);

// Running interval in nanoseconds
while hbt.elapse(100_000_000).unwrap() {
Expand All @@ -31,14 +32,6 @@ where
continue;
}

info!(
time = hbt.current_timestamp(),
bid = format!("{:.prec$}", depth.best_bid(), prec = price_prec),
ask = format!("{:.prec$}", depth.best_ask(), prec = price_prec),
position = position,
"Run"
);

let mid_price = (depth.best_bid() + depth.best_ask()) as f64 / 2.0;

let normalized_position = position / order_qty;
Expand Down
4 changes: 3 additions & 1 deletion rust/examples/gridtrading_backtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use hftbacktest::{
},
prelude::{HashMapMarketDepth, Interface},
};
use hftbacktest::backtest::recorder::BacktestRecorder;

mod algo;

Expand Down Expand Up @@ -46,6 +47,7 @@ fn main() {
let skew = 0.004;
let order_qty = 1.0;

gridtrading(&mut hbt, half_spread, grid_interval, skew, order_qty).unwrap();
let mut recorder = BacktestRecorder::new(&hbt);
gridtrading(&mut hbt, &mut recorder, half_spread, grid_interval, skew, order_qty).unwrap();
hbt.close().unwrap();
}
4 changes: 3 additions & 1 deletion rust/examples/gridtrading_live.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use hftbacktest::{
live::Bot,
prelude::{HashMapMarketDepth, Interface},
};
use hftbacktest::live::LoggingRecorder;

mod algo;

Expand Down Expand Up @@ -41,6 +42,7 @@ fn main() {
let skew = 0.004;
let order_qty = 1.0;

gridtrading(&mut hbt, half_spread, grid_interval, skew, order_qty).unwrap();
let mut recorder = LoggingRecorder::new();
gridtrading(&mut hbt, &mut recorder, half_spread, grid_interval, skew, order_qty).unwrap();
hbt.close().unwrap();
}
9 changes: 6 additions & 3 deletions rust/src/backtest/evs.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::mem;
use std::mem::{forget, size_of};
use std::{
mem,
mem::{forget, size_of},
};

#[derive(Clone, Copy)]
#[repr(C, align(32))]
Expand Down Expand Up @@ -31,7 +33,8 @@ fn aligned_vec_i64(count: usize) -> Box<[i64]> {
forget(aligned);

unsafe {
Vec::from_raw_parts(ptr as *mut i64, count, cap * size_of::<Align64>() / 8).into_boxed_slice()
Vec::from_raw_parts(ptr as *mut i64, count, cap * size_of::<Align64>() / 8)
.into_boxed_slice()
}
}

Expand Down
11 changes: 8 additions & 3 deletions rust/src/backtest/recorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,16 @@ impl Recorder for BacktestRecorder {

impl BacktestRecorder {
/// Constructs an instance of `BacktestRecorder`.
pub fn new(num_assets: usize) -> Self {
pub fn new<Q, MD, I>(hbt: &I) -> Self
where
Q: Sized + Clone,
I: Interface<Q, MD>,
MD: MarketDepth,
{
Self {
values: {
let mut vec = Vec::new();
for _ in 0..num_assets {
let mut vec = Vec::with_capacity(hbt.num_assets());
for _ in 0..hbt.num_assets() {
vec.push(Vec::new());
}
vec
Expand Down
3 changes: 2 additions & 1 deletion rust/src/live/bot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,8 @@ impl Interface<(), HashMapMarketDepth> for Bot<HashMapMarketDepth> {

#[inline]
fn state_values(&self, asset_no: usize) -> StateValues {
// fixme:
// todo: implement the missing fields. Trade values need to be changed to a rolling manner,
// unlike the current Python implementation, to support live trading.
StateValues {
position: *self.position.get(asset_no).unwrap_or(&0.0),
balance: 0.0,
Expand Down
1 change: 1 addition & 0 deletions rust/src/live/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod bot;
mod recorder;

pub use bot::{Bot, BotBuilder, BotError};
pub use recorder::LoggingRecorder;

/// Provides asset information for internal use.
#[derive(Clone)]
Expand Down
50 changes: 38 additions & 12 deletions rust/src/live/recorder.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
use std::{
fs::File,
io::{Error, Write},
path::Path,
};
use std::collections::{hash_map::Entry, HashMap};

use tracing::info;

Expand All @@ -11,12 +7,15 @@ use crate::{
prelude::Interface,
types::{Recorder, StateValues},
};
use crate::prelude::get_precision;

/// Provides logging of the live strategy's state values.
pub struct LiveRecorder;
pub struct LoggingRecorder {
state: HashMap<usize, (f32, StateValues)>,
}

impl Recorder for LiveRecorder {
type Error = Error;
impl Recorder for LoggingRecorder {
type Error = ();

fn record<Q, MD, I>(&mut self, hbt: &mut I) -> Result<(), Self::Error>
where
Expand All @@ -26,17 +25,44 @@ impl Recorder for LiveRecorder {
{
for asset_no in 0..hbt.num_assets() {
let depth = hbt.depth(asset_no);
let price_prec = get_precision(depth.tick_size());
let mid = (depth.best_bid() + depth.best_ask()) / 2.0;
let state_values = hbt.state_values(asset_no);
info!(%mid, ?state_values, "State");
let updated = match self.state.entry(asset_no) {
Entry::Occupied(mut entry) => {
let (prev_mid, prev_state_values) = entry.get();
if (*prev_mid != mid) || (*prev_state_values != state_values) {
*entry.get_mut() = (mid, state_values.clone());
true
} else {
false
}
}
Entry::Vacant(entry) => {
entry.insert((mid, state_values.clone()));
true
}
};
if updated {
info!(
%asset_no,
%mid,
bid = format!("{:.prec$}", depth.best_bid(), prec = price_prec),
ask = format!("{:.prec$}", depth.best_ask(), prec = price_prec),
?state_values,
"The state of asset number {asset_no} has been updated."
);
}
}
Ok(())
}
}

impl LiveRecorder {
/// Constructs an instance of `LiveRecorder`.
impl LoggingRecorder {
/// Constructs an instance of `LoggingRecorder`.
pub fn new() -> Self {
Self {}
Self {
state: Default::default(),
}
}
}
2 changes: 1 addition & 1 deletion rust/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ pub struct OrderResponse {
}

/// Provides state values.
#[derive(Debug)]
#[derive(PartialEq, Clone, Debug)]
pub struct StateValues {
pub position: f64,
pub balance: f64,
Expand Down

0 comments on commit 849775c

Please sign in to comment.