Crates.io | qust |
lib.rs | qust |
version | 0.1.4 |
source | src |
created_at | 2024-09-28 17:21:10.828444 |
updated_at | 2024-10-07 16:55:42.309557 |
description | A crate for finance quantative reserach |
homepage | |
repository | https://github.com/baiguoname/qust |
max_upload_size | |
id | 1390250 |
size | 305,248 |
Qust is a Rust libraries for building live-trading and back-test systems. It has the following features:
Accept kline flow, and return a target position.
Accept tick data flow, and return a target position.
Accept tick data flow, and return an order action.
Accept kline and tick flow, return a target positon or an order action.
Accept kline flow, and return a bool.(a least two of it make a strategy, one for open position, another for close)
Add filter conditions to an existed strategy.
Add algorithm method to an existed strategy.
Add order matching methods when backtest a strategy.
Add valitality manager to strategies.
Add portoflio manager to a pool of strategies. and so on.
See this notebook Example for more detail.
Add this to Cargo.toml
:
qust-derive = { version = ">=0.1" }
qust-ds = { version = ">=0.1" }
qust = { version = ">=0.1" }
qust-api = { version = ">=0.1"}
qust-io = { version = ">=0.1"}
serde = "*"
serde_json = "*"
itertools = "*"
typetag = "*"
tokio = "*"
ta = { version = "0.5.0" }
You can build a strategy basing on kline data and backtest in on kline:
use qust_derive::*;
use qust_ds::prelude::*;
use qust::prelude::*;
use qust_api::prelude::*;
use qust_io::prelude::*;
use ta::{ Next, indicators::SimpleMovingAverage as SMA };
#[ta_derive2]
pub struct TwoMaStra {
pub short_period: usize,
pub long_period: usize,
}
#[typetag::serde]
impl Ktn for TwoMaStra {
fn ktn(&self,_di: &Di) -> RetFnKtn {
let mut last_norm_hold = NormHold::No;
let mut short_ma = SMA::new(self.short_period).unwrap();
let mut long_ma = SMA::new(self.long_period).unwrap();
let mut last_short_value = 0f64;
let mut last_long_value = 0f64;
Box::new(move |di_kline| {
let c = di_kline.di.c()[di_kline.i] as f64;
let short_value = short_ma.next(c);
let long_value = long_ma.next(c);
match last_norm_hold {
NormHold::No if di_kline.i != 0 => {
if last_short_value < last_long_value && short_value >= long_value {
last_norm_hold = NormHold::Lo(1.);
}
}
NormHold::Lo(_) if short_value < long_value => {
last_norm_hold = NormHold::No;
}
_ => {}
}
last_short_value = short_value;
last_long_value = long_value;
last_norm_hold.clone()
})
}
}
#[tokio::main]
async fn main() {
let di = read_remote_kline_data().await;
let two_ma_stra = TwoMaStra { short_period: 9, long_period: 20 };
let two_ma_stra_ptm: Ptm = two_ma_stra.ktn_box().to_ktn().to_ptm();
let pnl_res_dt: PnlRes<dt> = two_ma_stra_ptm.bt_kline((&di, cs1));
pnl_res_dt.to_csv("pnl_res_dt.csv"); // save the pnl to local csv;
}
Or build strategy basing on tick data, then backtest it in tick data or put it on live trading:
use qust_derive::*;
use qust_ds::prelude::*;
use qust::prelude::*;
use qust_api::prelude::*;
use qust_io::prelude::*;
use ta::{ Next, indicators::SimpleMovingAverage as SMA };
#[ta_derive2]
pub struct TwoMaTickOrderAction;
impl ApiType for TwoMaTickOrderAction {
fn api_type(&self) -> RetFnApi {
let mut short_ma = SMA::new(1200).unwrap();
let mut long_ma = SMA::new(2400).unwrap();
let mut last_short_value = 0f64;
let mut last_long_value = 0f64;
Box::new(move |stream_api| {
let c = stream_api.tick_data.c as f64;
let short_value = short_ma.next(c);
let long_value = long_ma.next(c);
let hold = stream_api.hold.sum();
let mut res = OrderAction::No;
if hold == 0 {
match last_short_value != 0. && last_short_value < last_long_value && short_value >= long_value {
true => {
res = OrderAction::LoOpen(1, stream_api.tick_data.bid1);
}
false => (),
}
} else if hold > 0 && short_value < long_value {
res = OrderAction::ShClose(hold, stream_api.tick_data.ask1);
}
last_short_value = short_value;
last_long_value = long_value;
res
})
}
}
async fn backtest_tick() {
let tick_data = read_remote_tick_data().await;
let trade_info_vec: Vec<TradeInfo> = WithMatchBox {
data: TwoMaTickOrderAction,
match_box: Box::new(MatchSimple),
}
.bt_tick(&tick_data);
TickerTradeInfo {
ticker: aler,
trade_info_vec: trade_info_vec.clone()
}.into_pnl_res().to_csv("pnl_res_tick.csv");
}
#[tokio::main]
async fn main() {
backtest_tick().await;
// put it on live trading
let live_stra_pool = TwoMaTickOrderAction.to_live_stra_pool(vec![aler, eber]);
let ticker_contract_map = ["al2400", "eb2401"].config_parse();
let stra_api = StraApi::new( live_stra_pool, ticker_contract_map);
let account = SimnowAccount("171807", "Tangjihede00").config_parse();//account , password
let running_api = running_api_ctp(stra_api, account);
run_ctp(running_api).await;
}