Skip to content

Commit

Permalink
Merge pull request #84 from nkaz001/level3_mbo
Browse files Browse the repository at this point in the history
Level3 mbo
  • Loading branch information
nkaz001 authored Jun 17, 2024
2 parents 81960b4 + 87a6ae5 commit 3ba7b62
Show file tree
Hide file tree
Showing 17 changed files with 256 additions and 103 deletions.
9 changes: 4 additions & 5 deletions rust/examples/algo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{collections::HashMap, fmt::Debug};

use hftbacktest::prelude::*;

pub fn gridtrading<Q, MD, I, R>(
pub fn gridtrading<MD, I, R>(
hbt: &mut I,
recorder: &mut R,
relative_half_spread: f64,
Expand All @@ -13,10 +13,9 @@ pub fn gridtrading<Q, MD, I, R>(
max_position: f64,
) -> Result<(), i64>
where
Q: Sized + Clone,
MD: MarketDepth,
I: Interface<Q, MD>,
<I as Interface<Q, MD>>::Error: Debug,
I: Interface + BotTypedDepth<MD>,
<I as Interface>::Error: Debug,
R: Recorder,
<R as Recorder>::Error: Debug,
{
Expand All @@ -30,7 +29,7 @@ where
recorder.record(hbt).unwrap();
}

let depth = hbt.depth(0);
let depth = hbt.depth_typed(0);
let position = hbt.position(0);

if depth.best_bid_tick() == INVALID_MIN || depth.best_ask_tick() == INVALID_MAX {
Expand Down
2 changes: 1 addition & 1 deletion rust/examples/gridtrading_backtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use hftbacktest::{

mod algo;

fn prepare_backtest() -> MultiAssetMultiExchangeBacktest<QueuePos, HashMapMarketDepth> {
fn prepare_backtest() -> MultiAssetMultiExchangeBacktest<HashMapMarketDepth> {
let latency_data = (20240501..20240532)
.map(|date| DataSource::File(format!("latency_{date}.npz")))
.collect();
Expand Down
13 changes: 7 additions & 6 deletions rust/examples/gridtrading_backtest_args.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use algo::gridtrading;
use clap::Parser;

use algo::gridtrading;
use hftbacktest::{
backtest::{
assettype::LinearAsset,
models::{IntpOrderLatency, PowerProbQueueFunc3, ProbQueueModel, QueuePos},
reader::read_npz,
recorder::BacktestRecorder,
AssetBuilder,
assettype::LinearAsset,
DataSource,
ExchangeKind,
models::{IntpOrderLatency, PowerProbQueueFunc3, ProbQueueModel},
MultiAssetMultiExchangeBacktest,
reader::read_npz,
recorder::BacktestRecorder,
},
prelude::{ApplySnapshot, HashMapMarketDepth, Interface},
};
Expand Down Expand Up @@ -59,7 +60,7 @@ fn prepare_backtest(
lot_size: f32,
maker_fee: f64,
taker_fee: f64,
) -> MultiAssetMultiExchangeBacktest<QueuePos, HashMapMarketDepth> {
) -> MultiAssetMultiExchangeBacktest<HashMapMarketDepth> {
let latency_model = IntpOrderLatency::new(
latency_files
.iter()
Expand Down
108 changes: 83 additions & 25 deletions rust/src/backtest/backtest.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::HashMap, marker::PhantomData};
use std::{any::Any, collections::HashMap, marker::PhantomData};

use crate::{
backtest::{
Expand All @@ -8,8 +8,9 @@ use crate::{
BacktestError,
},
depth::{HashMapMarketDepth, MarketDepth},
prelude::OrderRequest,
prelude::{BotTypedDepth, OrderRequest},
types::{
BotTypedTrade,
BuildError,
Event,
Interface,
Expand All @@ -22,16 +23,21 @@ use crate::{
WAIT_ORDER_RESPONSE_NONE,
},
};
#[cfg(feature = "unstable_l3")]
use crate::{
backtest::proc::GenLocalProcessor,
depth::L3MarketDepth
};

/// [`MultiAssetMultiExchangeBacktest`] builder.
pub struct MultiAssetMultiExchangeBacktestBuilder<MD> {
local: Vec<Box<dyn LocalProcessor<MD>>>,
local: Vec<Box<dyn LocalProcessor<MD, Event>>>,
exch: Vec<Box<dyn Processor>>,
}

impl<MD> MultiAssetMultiExchangeBacktestBuilder<MD> {
/// Adds [`Asset`], which will undergo simulation within the backtester.
pub fn add(self, asset: Asset<dyn LocalProcessor<MD>, dyn Processor>) -> Self {
pub fn add(self, asset: Asset<dyn LocalProcessor<MD, Event>, dyn Processor>) -> Self {
let mut self_ = Self { ..self };
self_.local.push(asset.local);
self_.exch.push(asset.exch);
Expand Down Expand Up @@ -59,7 +65,7 @@ impl<MD> MultiAssetMultiExchangeBacktestBuilder<MD> {
pub struct MultiAssetMultiExchangeBacktest<MD> {
cur_ts: i64,
evs: EventSet,
local: Vec<Box<dyn LocalProcessor<MD>>>,
local: Vec<Box<dyn LocalProcessor<MD, Event>>>,
exch: Vec<Box<dyn Processor>>,
}

Expand All @@ -74,7 +80,7 @@ where
}
}

pub fn new(local: Vec<Box<dyn LocalProcessor<MD>>>, exch: Vec<Box<dyn Processor>>) -> Self {
pub fn new(local: Vec<Box<dyn LocalProcessor<MD, Event>>>, exch: Vec<Box<dyn Processor>>) -> Self {
let num_assets = local.len();
if local.len() != num_assets || exch.len() != num_assets {
panic!();
Expand Down Expand Up @@ -199,7 +205,7 @@ where
}
}

impl<MD> Interface<MD> for MultiAssetMultiExchangeBacktest<MD>
impl<MD> Interface for MultiAssetMultiExchangeBacktest<MD>
where
MD: MarketDepth,
{
Expand All @@ -225,15 +231,18 @@ where
self.local.get(asset_no).unwrap().state_values()
}

#[inline]
fn depth(&self, asset_no: usize) -> &MD {
&self.local.get(asset_no).unwrap().depth()
fn depth(&self, asset_no: usize) -> &dyn MarketDepth {
self.local.get(asset_no).unwrap().depth()
}

#[inline]
fn trade(&self, asset_no: usize) -> &Vec<Event> {
let local = self.local.get(asset_no).unwrap();
local.trade()
fn trade(&self, asset_no: usize) -> Vec<&dyn Any> {
self.local
.get(asset_no)
.unwrap()
.trade()
.iter()
.map(|ev| ev as &dyn Any)
.collect()
}

#[inline]
Expand Down Expand Up @@ -505,6 +514,27 @@ where
}
}

impl<MD> BotTypedDepth<MD> for MultiAssetMultiExchangeBacktest<MD>
where
MD: MarketDepth,
{
#[inline]
fn depth_typed(&self, asset_no: usize) -> &MD {
&self.local.get(asset_no).unwrap().depth()
}
}

impl<MD> BotTypedTrade<Event> for MultiAssetMultiExchangeBacktest<MD>
where
MD: MarketDepth,
{
#[inline]
fn trade_typed(&self, asset_no: usize) -> &Vec<Event> {
let local = self.local.get(asset_no).unwrap();
local.trade()
}
}

/// `MultiAssetSingleExchangeBacktest` builder.
pub struct MultiAssetSingleExchangeBacktestBuilder<Local, Exchange> {
local: Vec<Local>,
Expand All @@ -513,7 +543,7 @@ pub struct MultiAssetSingleExchangeBacktestBuilder<Local, Exchange> {

impl<Local, Exchange> MultiAssetSingleExchangeBacktestBuilder<Local, Exchange>
where
Local: LocalProcessor<HashMapMarketDepth> + 'static,
Local: LocalProcessor<HashMapMarketDepth, Event> + 'static,
Exchange: Processor + 'static,
{
/// Adds [`Asset`], which will undergo simulation within the backtester.
Expand Down Expand Up @@ -558,7 +588,7 @@ pub struct MultiAssetSingleExchangeBacktest<MD, Local, Exchange> {
impl<MD, Local, Exchange> MultiAssetSingleExchangeBacktest<MD, Local, Exchange>
where
MD: MarketDepth,
Local: LocalProcessor<MD>,
Local: LocalProcessor<MD, Event>,
Exchange: Processor,
{
pub fn builder() -> MultiAssetSingleExchangeBacktestBuilder<Local, Exchange> {
Expand Down Expand Up @@ -688,10 +718,10 @@ where
}
}

impl<MD, Local, Exchange> Interface<MD> for MultiAssetSingleExchangeBacktest<MD, Local, Exchange>
impl<MD, Local, Exchange> Interface for MultiAssetSingleExchangeBacktest<MD, Local, Exchange>
where
MD: MarketDepth,
Local: LocalProcessor<MD>,
Local: LocalProcessor<MD, Event>,
Exchange: Processor,
{
type Error = BacktestError;
Expand All @@ -716,15 +746,18 @@ where
self.local.get(asset_no).unwrap().state_values()
}

#[inline]
fn depth(&self, asset_no: usize) -> &MD {
&self.local.get(asset_no).unwrap().depth()
fn depth(&self, asset_no: usize) -> &dyn MarketDepth {
self.local.get(asset_no).unwrap().depth()
}

#[inline]
fn trade(&self, asset_no: usize) -> &Vec<Event> {
let local = self.local.get(asset_no).unwrap();
local.trade()
fn trade(&self, asset_no: usize) -> Vec<&dyn Any> {
self.local
.get(asset_no)
.unwrap()
.trade()
.iter()
.map(|ev| ev as &dyn Any)
.collect()
}

#[inline]
Expand Down Expand Up @@ -996,3 +1029,28 @@ where
self.local.get(asset_no).unwrap().order_latency()
}
}

impl<MD, Local, Exchange> BotTypedDepth<MD> for MultiAssetSingleExchangeBacktest<MD, Local, Exchange>
where
MD: MarketDepth,
Local: LocalProcessor<MD, Event>,
Exchange: Processor,
{
#[inline]
fn depth_typed(&self, asset_no: usize) -> &MD {
&self.local.get(asset_no).unwrap().depth()
}
}

impl<MD, Local, Exchange> BotTypedTrade<Event> for MultiAssetSingleExchangeBacktest<MD, Local, Exchange>
where
MD: MarketDepth,
Local: LocalProcessor<MD, Event>,
Exchange: Processor,
{
#[inline]
fn trade_typed(&self, asset_no: usize) -> &Vec<Event> {
let local = self.local.get(asset_no).unwrap();
local.trade()
}
}
6 changes: 3 additions & 3 deletions rust/src/backtest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ pub mod recorder;

mod evs;

#[cfg(features = "unstable_l3")]
pub mod l3backtest;
#[cfg(feature = "unstable_l3")]
mod l3backtest;

#[derive(Error, Debug)]
pub enum BacktestError {
Expand Down Expand Up @@ -209,7 +209,7 @@ where
}

/// Builds an `Asset`.
pub fn build(self) -> Result<Asset<dyn LocalProcessor<MD>, dyn Processor>, BuildError> {
pub fn build(self) -> Result<Asset<dyn LocalProcessor<MD, Event>, dyn Processor>, BuildError> {
let ob_local_to_exch = OrderBus::new();
let ob_exch_to_local = OrderBus::new();

Expand Down
6 changes: 2 additions & 4 deletions rust/src/backtest/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ mod latencies;
mod queue;

pub use latencies::{ConstantLatency, IntpOrderLatency, LatencyModel};

#[cfg(feature = "unstable_l3")]
pub use queue::{L3OrderId, L3OrderSource, L3QueueModel};
pub use queue::{
LogProbQueueFunc,
LogProbQueueFunc2,
Expand All @@ -14,6 +15,3 @@ pub use queue::{
QueuePos,
RiskAdverseQueueModel,
};

#[cfg(feature = "unstable_l3")]
pub use queue::{L3OrderId, L3OrderSource, L3QueueModel};
21 changes: 11 additions & 10 deletions rust/src/backtest/models/queue.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{any::Any, marker::PhantomData};
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::{
any::Any,
collections::{hash_map::Entry, HashMap},
marker::PhantomData,
};

use crate::{
backtest::BacktestError,
Expand Down Expand Up @@ -319,6 +321,7 @@ pub enum L3OrderSource {
Backtesting,
}

#[cfg(feature = "unstable_l3")]
impl AnyClone for L3OrderSource {
fn as_any(&self) -> &dyn Any {
self
Expand Down Expand Up @@ -531,11 +534,7 @@ impl L3QueueModel {
Ok(())
}

pub fn fill(
&mut self,
order_id: L3OrderId,
delete: bool,
) -> Result<Vec<Order>, BacktestError> {
pub fn fill(&mut self, order_id: L3OrderId, delete: bool) -> Result<Vec<Order>, BacktestError> {
let (side, order_price_tick) = self
.orders
.remove(&order_id)
Expand All @@ -550,7 +549,8 @@ impl L3QueueModel {
let mut i = 0;
while i < priority.len() {
let order_in_q = priority.get(i).unwrap();
let order_source = order_in_q.q
let order_source = order_in_q
.q
.as_any()
.downcast_ref::<L3OrderSource>()
.unwrap();
Expand Down Expand Up @@ -581,7 +581,8 @@ impl L3QueueModel {
let mut i = 0;
while i < priority.len() {
let order_in_q = priority.get(i).unwrap();
let order_source = order_in_q.q
let order_source = order_in_q
.q
.as_any()
.downcast_ref::<L3OrderSource>()
.unwrap();
Expand Down
7 changes: 3 additions & 4 deletions rust/src/backtest/proc/l3_local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ where
}
}

impl<AT, LM, MD> LocalProcessor<MD> for L3Local<AT, LM, MD>
impl<AT, LM, MD> LocalProcessor<MD, L3Event> for L3Local<AT, LM, MD>
where
AT: AssetType,
LM: LatencyModel,
Expand Down Expand Up @@ -215,9 +215,8 @@ where
&self.orders
}

fn trade(&self) -> &Vec<Event> {
todo!()
// &self.trades
fn trade(&self) -> &Vec<L3Event> {
&self.trades
}

fn clear_last_trades(&mut self) {
Expand Down
Loading

0 comments on commit 3ba7b62

Please sign in to comment.