| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338 |
- use std::cmp::{max, min};
- use std::collections::HashMap;
- use std::ops::{Div, Mul};
- use std::str::FromStr;
- use chrono::Utc;
- use rust_decimal::Decimal;
- use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
- use rust_decimal_macros::dec;
- use crate::model::{DealRecord, LocalPosition, OrderInfo, TraderMsg};
- use crate::utils;
- use tracing::{info, error, warn, instrument};
- use reqwest::{Client};
- use tokio::spawn;
- use global::params::Params;
- use standard::{OrderCommand};
- #[derive(Debug)]
- pub struct Strategy {
- // 各类时间戳和时延,我们都改成了毫秒级
- pub _print_time: i64, // 上次打印时间
- pub _print_interval: i64, // 打印时延
- pub _start_time: i64, // 开始时间
- pub local_time: i64, // 本地时间
- pub local_start_time: i64, // 本地开始时间
- pub post_open_time: i64, // 上次提交订单的时间戳
- pub post_open_interval: i64, // 提交订单时延
- pub _check_local_orders_time: i64, // 上次查单时间
- pub _check_local_orders_interval: i64, // 查单间距,原文是秒级,这里改成毫秒级
- pub in_cancel: HashMap<String, i64>, // 撤单队列
- pub cancel_wait_interval: i64, // 取消等待时延
- pub in_check: HashMap<String, i64>, // 查单队列
- pub check_wait_interval: i64, // 检测时延
- pub request_limit_check_time: i64, // 上次检查订单的时间
- pub request_limit_check_interval: i64, // 原文是秒级,这里改成毫秒级
- pub request_count: i64, // 记录请求次数,原文的request_num
- pub request_order_count: i64, // 记录下单次数,原文的request_order_num
- pub request_over_log_interval: i64, // 两次超时打印之间的间隔
- pub request_over_log_time: i64, // 上次打印时间
- pub limit_requests_num: i64, // 单位(时延)时间内请求次数上限
- pub limit_order_requests_num: i64, // 单位(时延)时间内下单次数上限
- pub _req_num_per_window: i64, // 单位(时延)时间内请求上限窗口
- pub params: Params, //
- pub exchange: String, //
- pub broker_id: String, //
- pub trade_name: String, //
- pub ref_exchange_length: usize, //
- pub ref_name: Vec<String>, //
- pub maker_mode: String, //
- pub local_orders: HashMap<String, OrderInfo>, // 本地订单
- pub pos: LocalPosition, //
- pub long_hold_value: Decimal, //
- pub short_hold_value: Decimal, //
- pub equity: Decimal, //
- pub coin: Decimal, //
- pub cash: Decimal, //
- pub start_equity: Decimal, //
- pub start_coin: Decimal, //
- pub start_cash: Decimal, //
- pub max_equity: Decimal, //
- pub local_profit: Decimal, //
- pub total_amount: Decimal, //
- pub is_ready: bool, // 程序是否已经准备好,ready
- pub _is_print: bool, //
- pub _min_amount_value: Decimal, //
- pub _max_amount_value: Decimal, //
- pub mp_ema: Decimal, // 原文的mp_ewma
- pub mp: Decimal, //
- pub bp: Decimal, //
- pub ap: Decimal, //
- pub ref_price: Decimal, //
- pub ref_bp: Decimal, //
- pub ref_ap: Decimal, //
- pub step_size: Decimal, // 原文的stepSize
- pub tick_size: Decimal, // 原文的tickSize
- pub max_pos_rate: Decimal, // 原文的maxPos,其实是最大持仓比例
- pub profit: Decimal, //
- pub daily_return: Decimal, //
- pub adjust_lever_rate: Decimal, // 原文的adjust_leverrate
- pub lever_rate: Decimal, // 原文的leverrate
- pub long_pos_bias: Decimal, //
- pub short_pos_bias: Decimal, //
- pub long_hold_rate: Decimal, //
- pub short_hold_rate: Decimal, //
- pub max_long_value: Decimal, // 最大做多持仓
- pub max_short_value: Decimal, // 最大做空持仓
- pub open_dist: Vec<Decimal>, // 开仓相关价格
- pub close_dist: Vec<Decimal>, // 平仓相关价格
- pub trade_close_dist: Decimal, //
- pub trade_open_dist: Decimal, //
- pub ref_index: usize, //
- pub predict: Decimal, //
- pub predict_alpha: Decimal, //
- pub post_side: i64, // 交易方向
- pub trade_vol_24h_w: Decimal, // 24小时成交额(单位:万)
- pub grid: Decimal, // 网格数量
- }
- impl Strategy {
- pub fn new(params: &Params, is_print: bool) -> Self {
- if params.ref_exchange.len() != params.ref_pair.len(){
- error!("参考盘口数不等于参考品种数,退出,请检查配置!");
- panic!("参考盘口数不等于参考品种数,退出,请检查配置!");
- }
- // strategy的初始化,里面已经有一些参数初始化了
- let mut strategy = Self {
- _print_time: 0,
- _start_time: 0,
- local_time: 0,
- local_start_time: 0,
- request_count: 0,
- request_order_count: 0,
- request_over_log_interval: 60 * 1000,
- request_over_log_time: 0,
- _print_interval: 5 * 1000,
- in_cancel: Default::default(),
- cancel_wait_interval: (0.2 * 1000f64).to_i64().unwrap(),
- in_check: Default::default(),
- check_wait_interval: 10 * 1000,
- _check_local_orders_time: 0,
- _check_local_orders_interval: 0,
- request_limit_check_time: 0,
- request_limit_check_interval: 0,
- limit_requests_num: 0,
- limit_order_requests_num: 0,
- _req_num_per_window: 0,
- post_open_time: 0,
- post_open_interval: 0,
- params: params.clone(),
- exchange: params.exchange.clone(),
- broker_id: params.broker_id.clone(),
- trade_name: "".to_string(),
- ref_exchange_length: params.ref_exchange.len(),
- ref_name: vec![],
- maker_mode: "free".to_string(),
- local_orders: Default::default(),
- pos: LocalPosition {
- long_pos: Default::default(),
- short_pos: Default::default(),
- long_avg: Default::default(),
- short_avg: Default::default(),
- },
- long_hold_value: Default::default(),
- short_hold_value: Default::default(),
- equity: Default::default(),
- coin: Default::default(),
- cash: Default::default(),
- start_equity: Default::default(),
- start_coin: Default::default(),
- start_cash: Default::default(),
- max_equity: Default::default(),
- local_profit: Default::default(),
- total_amount: Default::default(),
- is_ready: false,
- _is_print: is_print,
- _min_amount_value: dec!(5.0),
- _max_amount_value: dec!(10000.0),
- mp_ema: Default::default(),
- mp: Default::default(),
- bp: Default::default(),
- ap: Default::default(),
- ref_price: Default::default(),
- ref_bp: Default::default(),
- ref_ap: Default::default(),
- step_size: dec!(1e-10),
- tick_size: dec!(1e-10),
- max_pos_rate: Default::default(),
- profit: Default::default(),
- daily_return: Default::default(),
- adjust_lever_rate: Decimal::ONE,
- lever_rate: Default::default(),
- long_pos_bias: Default::default(),
- short_pos_bias: Default::default(),
- long_hold_rate: Default::default(),
- short_hold_rate: Default::default(),
- max_long_value: Default::default(),
- max_short_value: Default::default(),
- open_dist: vec![],
- close_dist: vec![],
- trade_close_dist: params.close,
- trade_open_dist: params.open,
- ref_index: 0,
- predict: Default::default(),
- predict_alpha: Default::default(),
- post_side: 0,
- trade_vol_24h_w: Default::default(),
- grid: Decimal::from(params.grid),
- };
- // 交易名字
- strategy.trade_name = format!("{}@{}", params.exchange.clone(), params.pair.clone());
- // 参考交易所的trade_name
- for index in 0..strategy.ref_exchange_length {
- strategy.ref_name.push(format!("{}@{}", params.ref_exchange[index], params.ref_pair[index]));
- }
- // 杠杆比例处理
- strategy.lever_rate = params.lever_rate;
- if strategy.exchange.contains("spot") {
- strategy.lever_rate = min(params.lever_rate, Decimal::ONE);
- }
- // 各类时间戳
- let now = Utc::now();
- strategy.local_time = now.timestamp_millis();
- strategy.local_start_time = now.timestamp_millis();
- strategy._print_time = now.timestamp_millis();
- strategy._start_time = now.timestamp_millis();
- // 检查订单的时间戳
- strategy._check_local_orders_time = now.timestamp_millis();
- strategy._check_local_orders_interval = 10 * 1000;
- // 下单的相关限制处理
- strategy.request_limit_check_time = now.timestamp_millis();
- strategy.request_limit_check_interval = 10 * 1000;
- // 求得正常请求数量和下单请求数量(interval时间内)
- let request_limit_check_interval_per_second = strategy.request_limit_check_interval / 1000;
- strategy.limit_requests_num = utils::get_limit_requests_num_per_second(params.exchange.clone()) * (request_limit_check_interval_per_second);
- strategy.limit_order_requests_num = utils::get_limit_order_requests_num_per_second(params.exchange.clone()) * (request_limit_check_interval_per_second);
- // 开仓下单间隔 均匀下单机会
- strategy.post_open_time = now.timestamp_millis();
- let post_open_interval_per_second = Decimal::ONE.div(Decimal::from_i64(utils::get_limit_order_requests_num_per_second(params.exchange.clone())).unwrap());
- strategy.post_open_interval = dec!(1000).mul(post_open_interval_per_second).to_i64().unwrap();
- info!("策略模块初始化完成!");
- return strategy;
- }
- // 更新当前strategy的各类信息
- #[instrument(skip(self, trader_msg), level="TRACE")]
- pub fn _update_data(&mut self, trader_msg: &TraderMsg) -> bool {
- // debug!(?self);
- // debug!(?trader_msg);
- self.local_orders.clear();
- self.local_orders = trader_msg.orders.clone();
- // position信息更新
- if self.pos.long_pos != trader_msg.position.long_pos {
- self.pos.long_pos = trader_msg.position.long_pos;
- self.pos.long_avg = trader_msg.position.long_avg;
- }
- if self.pos.short_pos != trader_msg.position.short_pos {
- self.pos.short_pos = trader_msg.position.short_pos;
- self.pos.short_avg = trader_msg.position.short_avg;
- }
- // debug!(?self.pos);
- // 价格值处理
- self.bp = trader_msg.market[global::public_params::BID_PRICE_INDEX];
- self.ap = trader_msg.market[global::public_params::ASK_PRICE_INDEX];
- self.mp = (self.bp + self.ap) * dec!(0.5);
- // 中间价的ema值处理
- if self.mp_ema.eq(&Decimal::ZERO) {
- self.mp_ema = self.mp;
- } else {
- self.mp_ema = self.mp_ema * dec!(0.999) + self.mp * dec!(0.001);
- }
- // debug!(?self.bp, ?self.ap, ?self.mp, ?self.mp_ema);
- // 动态杠杆调节
- if self.mp > self.mp_ema {
- self.adjust_lever_rate = Decimal::ONE;
- } else {
- self.adjust_lever_rate = dec!(0.8);
- }
- // debug!(?self.adjust_lever_rate);
- // 当前持仓价值处理
- self.long_hold_value = self.pos.long_pos * self.mp;
- self.short_hold_value = self.pos.short_pos * self.mp;
- // debug!(?self.long_hold_value, ?self.short_hold_value);
- // 分现货或合约计算最大开仓价值
- if self.exchange.contains("spot") {
- self.max_long_value = trader_msg.cash * self.lever_rate * self.adjust_lever_rate;
- self.max_short_value = trader_msg.coin * self.lever_rate * self.adjust_lever_rate * self.mp;
- } else {
- self.max_long_value = self.equity * self.lever_rate * self.adjust_lever_rate;
- self.max_short_value = self.max_long_value;
- }
- // debug!(?self.max_long_value, ?self.max_short_value, ?self.equity, ?self.lever_rate, ?self.adjust_lever_rate);
- // 做市模式识别
- if self.ref_name[self.ref_index].eq(&self.trade_name) {
- self.maker_mode = "free".to_string();
- } else {
- self.maker_mode = "follow".to_string();
- }
- // debug!(?self.maker_mode);
- // 参考价格
- if trader_msg.ref_price.len() == 0 {
- self.ref_bp = self.bp;
- self.ref_ap = self.ap;
- self.ref_price = self.mp;
- } else {
- self.ref_bp = trader_msg.ref_price[self.ref_index][0];
- self.ref_ap = trader_msg.ref_price[self.ref_index][1];
- self.ref_price = (self.ref_bp + self.ref_ap) * dec!(0.5);
- }
- // debug!(?self.ref_bp, ?self.ref_ap, %self.ref_price);
- // spread
- let temp_predict = trader_msg.predict * self.predict_alpha;
- self.predict = utils::clip(temp_predict, -self.trade_open_dist, self.trade_open_dist);
- // debug!(?self.predict);
- // 计算当前账户cash和coin
- self.coin = trader_msg.coin;
- self.cash = trader_msg.cash;
- self.equity = trader_msg.cash + trader_msg.coin * self.mp;
- if self.equity > self.max_equity {
- self.max_equity = self.equity;
- }
- // debug!(?self.coin, ?self.cash, ?self.equity, ?self.max_equity);
- // 总可开数量
- self.total_amount = self.equity * self.lever_rate * self.adjust_lever_rate / self.mp;
- self.total_amount = utils::fix_amount(self.total_amount, self.step_size);
- // debug!(?self.total_amount);
- if self.total_amount.eq(&Decimal::ZERO) {
- error!("总可开数量低于一张,请尝试加大杠杆倍数或资金!equity={}, lever_rate={}, adjust_lever_rate={}, mp={}, step_size={}",
- self.equity, self.lever_rate, self.adjust_lever_rate, self.mp, self.step_size);
- return false;
- }
- // 求最大pos
- if self.equity > Decimal::ZERO {
- let max_pos_rate = max(self.pos.long_pos, self.pos.short_pos) * self.mp / self.equity;
- if max_pos_rate > self.max_pos_rate {
- self.max_pos_rate = max_pos_rate;
- }
- // debug!(?max_pos_rate, ?self.max_pos_rate);
- }
- return true;
- }
- // 打印状态信息
- // 耗时700微秒
- #[instrument(skip(self), level="TRACE")]
- pub fn _print_summary(&mut self) {
- self.mp.rescale(6);
- self.ref_price.rescale(6);
- self.equity.rescale(3);
- self.cash.rescale(3);
- let mut value = self.coin * self.mp;
- value.rescale(3);
- let mut price_bias = Decimal::ONE_HUNDRED * (self.ref_price - self.mp) / self.mp;
- price_bias.rescale(2);
- // 盈亏计算
- self.profit = if self.start_equity.gt(&Decimal::ZERO) {
- ((self.equity - self.start_equity) / self.start_equity) * Decimal::ONE_HUNDRED
- } else {
- Decimal::ZERO
- };
- self.profit.rescale(2);
- // 多仓杠杆计算
- let mut long_pos_leverage = if self.equity.gt(&Decimal::ZERO) {
- self.pos.long_pos * self.mp / self.equity
- } else {
- Decimal::ZERO
- };
- long_pos_leverage.rescale(3);
- // 多仓浮盈计算
- self.long_pos_bias = if self.pos.long_pos.gt(&Decimal::ZERO) {
- Decimal::ONE_HUNDRED - Decimal::ONE_HUNDRED * self.pos.long_avg / self.mp
- } else {
- Decimal::ZERO
- };
- self.long_pos_bias.rescale(2);
- // 空仓杠杆计算
- let mut short_pos_leverage = if self.equity.gt(&Decimal::ZERO) {
- self.pos.short_pos * self.mp / self.equity
- } else {
- Decimal::ZERO
- };
- short_pos_leverage.rescale(3);
- // 多仓浮盈计算
- self.short_pos_bias = if self.pos.short_pos.gt(&Decimal::ZERO) {
- Decimal::ONE_HUNDRED - Decimal::ONE_HUNDRED * self.pos.short_avg / self.mp
- } else {
- Decimal::ZERO
- };
- let run_time = Utc::now().timestamp_millis() - self._start_time;
- let run_time_day = Decimal::from(run_time) / (dec!(86400000));
- self.daily_return = self.profit / run_time_day;
- self.daily_return.rescale(2);
- self.short_pos_bias.rescale(2);
- self.trade_open_dist.rescale(6);
- self.trade_close_dist.rescale(6);
- self.predict.rescale(5);
- // 挂单列表长度
- let o_num = self.local_orders.len();
- let mut msg = String::new();
- msg.push_str("当前状态: ");
- msg.push_str(format!("[品种 {}, 现价 {:?}, 定价 {:?}, 偏差 {:?}%, 杠杆 {:?}, 动态{:?}, 最大{:?}, 预测 {:?}, 预估24H成交额 {:?}万], ",
- self.params.pair, self.mp, self.ref_price, price_bias, self.lever_rate,
- self.adjust_lever_rate, self.max_pos_rate, self.predict, self.trade_vol_24h_w).as_str());
- msg.push_str(format!("[净值 {:?}, Cash {:?}, Coin(价值) {:?}, 日化 {:?}%], ", self.equity, self.cash, value, self.daily_return).as_str());
- msg.push_str(format!("[推算利润 {:?}, 盈亏 {:?}%, 做多杠杆 {:?}%, 做多浮盈 {:?}%, 做空杠杆 {:?}%, 做空浮盈 {:?}%], ",
- self.local_profit, self.profit, long_pos_leverage, self.long_pos_bias, short_pos_leverage, self.short_pos_bias).as_str());
- msg.push_str(format!("[请求 {:?}, 上限{:?}次/10秒], ", self._req_num_per_window, self.limit_order_requests_num).as_str());
- msg.push_str(format!("[当前参数, 开仓 {:?}, 平仓 {:?}, 方向 {:?}, 参考 {:?}, 模式 {:?}], ",
- self.trade_open_dist, self.trade_close_dist, self.post_side, self.ref_name[self.ref_index], self.maker_mode).as_str());
- msg.push_str(format!("[挂单列表,共{:?}单, ", o_num).as_str());
- for (_, order) in &self.local_orders {
- let mut order_value = order.amount * self.mp;
- let mut order_lever_rate = if self.equity.gt(&Decimal::ZERO) {
- order.amount * self.mp / self.equity
- } else {
- Decimal::ZERO
- };
- let mut order_bias = Decimal::ONE_HUNDRED * (order.price - self.mp) / self.mp;
- order_value.rescale(2);
- order_lever_rate.rescale(3);
- order_bias.rescale(3);
- msg.push_str(format!("[{:?} {:?} {:?}, 杠杆{:?}X 价值{:?}U 价格{:?} 偏离{:?}%]",
- order.symbol, order.client_id, order.side, order_lever_rate, order_value, order.price, order_bias).as_str());
- }
- msg.push_str("]");
- info!("{}", msg);
- }
- // 取消目标方向订单,原文是_cancel_targit_side_orders
- #[instrument(skip(self, command), level="TRACE")]
- pub fn _cancel_target_side_orders(&self, command: &mut OrderCommand) {
- // 要取消的目标方向
- let target_side = vec![
- "kd".to_string(),
- "kk".to_string(),
- "pd".to_string(),
- "pk".to_string()
- ];
- // debug!(?self.local_orders);
- for client_id in self.local_orders.keys() {
- let order = self.local_orders.get(client_id).unwrap();
- // 如果不属于目标方向,则不需要取消
- if !target_side.contains(&order.side.clone()) {
- continue;
- }
- // 属于目标方向,则取消
- let key = format!("Cancel{}", client_id);
- let value = vec![order.client_id.clone(), order.order_id.clone()];
- command.cancel.insert(key, value);
- }
- // debug!(?command);
- }
- // 生成各类挂单价格,原文是gen_dist
- #[instrument(skip(self), level="TRACE")]
- pub fn generate_dist(&mut self) {
- let open = self.trade_open_dist;
- let close = self.trade_close_dist;
- let pos_rate = vec![self.long_hold_rate, self.short_hold_rate];
- let ref_bp = self.ref_bp;
- let ref_ap = self.ref_ap;
- let predict = self.predict;
- let grid = self.grid;
- let mode = self.maker_mode.clone();
- // 平仓相关
- let mut mp = (ref_bp + ref_ap) * dec!(0.5);
- let mut buy_start = mp;
- let mut sell_start = mp;
- let mut avoid = min(dec!(0.0005), close * dec!(0.5));
- let mut close_dist = vec![
- buy_start * (Decimal::ONE + predict - close + avoid), // buy upper
- buy_start * (Decimal::ONE + predict - close - avoid), // buy lower
- sell_start * (Decimal::ONE + predict + close - avoid), // sell lower
- sell_start * (Decimal::ONE + predict + close + avoid), // sell upper
- ];
- // debug!(?mp, ?buy_start, ?sell_start, ?avoid, ?close_dist);
- // 自由做市模式
- if mode == "free".to_string() {
- buy_start = ref_bp;
- sell_start = ref_ap;
- }
- // 跟随做市模式
- else if mode == "follow".to_string() {
- mp = (ref_bp + ref_ap) * dec!(0.5);
- buy_start = mp;
- sell_start = mp;
- } else {
- error!("未知做市类型:mode={}", mode);
- panic!("未知做市类型:mode={}", mode);
- }
- // debug!(?mode, ?buy_start, ?sell_start, ?mp);
- // 开仓相关
- avoid = min(dec!(0.001), open * dec!(0.05));
- // 持仓偏移
- let buy_shift = Decimal::ONE + pos_rate[0] * grid;
- let sell_shift = Decimal::ONE + pos_rate[1] * grid;
- let mut open_dist = vec![
- buy_start * (Decimal::ONE + predict - open * buy_shift + avoid), // buy upper
- buy_start * (Decimal::ONE + predict - open * buy_shift - avoid), // buy lower
- sell_start * (Decimal::ONE + predict + open * sell_shift - avoid), // sell lower
- sell_start * (Decimal::ONE + predict + open * sell_shift + avoid), // sell upper
- ];
- // debug!(?avoid, ?buy_shift, ?sell_shift, ?avoid, ?open_dist);
- // 修复价格
- for open_price in &mut open_dist {
- *open_price = utils::fix_price(*open_price, self.tick_size);
- }
- for close_price in &mut close_dist {
- *close_price = utils::fix_price(*close_price, self.tick_size);
- }
- self.open_dist = open_dist.clone();
- self.close_dist = close_dist.clone();
- // debug!(?open_dist);
- // debug!(?close_dist);
- }
- // 统计请求次数
- #[instrument(skip(self, command), level="TRACE")]
- pub fn _update_request_num(&mut self, command: &OrderCommand) {
- // debug!(?command);
- // debug!(?self.request_order_count, ?self.request_count);
- let order_count = (command.limits_open.len() + command.limits_close.len()).to_i64().unwrap();
- let request_count = order_count + (command.cancel.len() + command.check.len()).to_i64().unwrap();
- self.request_order_count += order_count;
- self.request_count += request_count;
- // debug!(?self.request_order_count, ?self.request_count);
- }
- // 根据平均请求次数限制开仓下单
- #[instrument(skip(self, command), level="TRACE")]
- pub fn _check_request_limit(&mut self, command: &mut OrderCommand) {
- let mut msg = String::new();
- // 如果当前请求数超过限制
- if self.request_count > self.limit_requests_num {
- command.cancel.clear();
- command.check.clear();
- command.limits_open.clear();
- command.limits_close.clear();
- msg = format!("请求频率溢出,程序禁止任何操作!({}/{})", self.request_count, self.limit_requests_num);
- } else if self.request_order_count >= self.limit_order_requests_num { // 100%超过下单频率,则不再进行平仓挂单
- command.limits_close.clear();
- command.limits_open.clear();
- msg = format!("超过100%下单频率!程序禁止开平仓!({}/{})", self.request_order_count, self.limit_order_requests_num);
- } else if self.request_count > self.limit_requests_num * 5 / 10
- && self.request_order_count > self.limit_order_requests_num * 8 / 10 { // 超过80%,直接取消limits_open的下单指令
- command.limits_open.clear();
- msg = format!("超过80%下单频率,程序禁止开仓!({}/{})", self.request_order_count, self.limit_order_requests_num);
- }
- // 检查是否需要打印msg
- if !msg.is_empty() && self.local_time - self.request_over_log_time > self.request_over_log_interval {
- warn!("{}", msg);
- self.request_over_log_time = self.local_time;
- }
- }
- // 新增正在撤单、检查撤单队列,释放过时限制
- #[instrument(skip(self), level="TRACE")]
- pub fn _update_in_cancel(&mut self, command: &mut OrderCommand) {
- let mut new_cancel: HashMap<String, Vec<String>> = HashMap::new();
- for cancel_name in command.cancel.keys() {
- let cancel = command.cancel.get(cancel_name).unwrap();
- let client_id = cancel[0].clone();
- let mut need_limit_cancel = true;
- let order_some = self.local_orders.get(&client_id);
- // 判断是否在本地挂单表中
- if let Some(order) = order_some {
- // 如果订单创建时间大于100ms,才能有撤单操作
- if self.local_time - order.create_time < 100 {
- need_limit_cancel = false;
- }
- }
- if need_limit_cancel {
- // 如果已经不在撤销队列里,增加到撤销队列
- if self.in_cancel.get(&client_id).is_none() {
- self.in_cancel.insert(client_id.clone(), self.local_time);
- new_cancel.insert(cancel_name.clone(), cancel.clone());
- }
- }
- }
- // debug!(?command);
- command.cancel = new_cancel;
- // debug!(?command);
- // 释放撤单限制
- self._release_in_cancel();
- }
- // 维护查单队列,检查是否在撤单
- #[instrument(skip(self), level="TRACE")]
- pub fn _release_in_check(&mut self) {
- // debug!(?self.in_check);
- // 为什么要移出来:Rust不允许边循环边修改map
- let mut to_remove = Vec::new();
- for client_id in self.in_check.keys() {
- let time = self.in_check.get(client_id).unwrap();
- // 等待不超时,就不移除
- if self.local_time - time <= self.check_wait_interval {
- continue;
- }
- // 等待超时,就移除正在撤单队列
- // debug!("移除查单队列:{}", client_id.clone());
- to_remove.push(client_id.clone());
- }
- // 在后面的循环中去单独处理map的更新
- for client_id in to_remove {
- self.in_check.remove(&client_id);
- }
- // debug!(?self.in_check);
- }
- // 检查是否正在撤单
- #[instrument(skip(self), level="TRACE")]
- pub fn _release_in_cancel(&mut self) {
- // debug!(?self.in_cancel);
- // 为什么要移出来:Rust不允许边循环边修改map
- let mut to_remove = Vec::new();
- for client_id in self.in_cancel.keys() {
- let time = self.in_cancel.get(client_id).unwrap();
- // 等待不超时,就不移除
- if self.local_time - time <= self.cancel_wait_interval {
- continue;
- }
- // 等待超时,就移除正在撤单队列
- // debug!("等待超过后移除正在撤单队列:{}", client_id.clone());
- to_remove.push(client_id.clone());
- }
- // 在后面的循环中去单独处理map的更新
- for client_id in to_remove {
- self.in_cancel.remove(&client_id);
- }
- // debug!(?self.in_cancel);
- }
- // 刷新请求限制
- pub fn _refresh_request_limit(&mut self) {
- if self.local_time - self.request_limit_check_time < self.request_limit_check_interval {
- return;
- }
- self._req_num_per_window = self.request_count;
- self.request_count = 0;
- self.request_order_count = 0;
- self.request_limit_check_time = self.local_time;
- }
- // 刷新持仓比例
- #[instrument(skip(self), level="TRACE")]
- pub fn _pos_rate(&mut self) {
- // debug!(?self);
- if self.max_long_value > Decimal::ZERO {
- self.long_hold_rate = self.long_hold_value / self.max_long_value;
- // debug!(?self.long_hold_rate);
- }
- if self.max_short_value > Decimal::ZERO {
- self.short_hold_rate = self.short_hold_value / self.max_short_value;
- // debug!(?self.short_hold_rate);
- }
- }
- // 当退出时调用,全撤全平 准备退出
- pub fn on_exit(&mut self, trader_msg: &TraderMsg) -> OrderCommand {
- let mut command = OrderCommand::new();
- if self._update_data(trader_msg) {
- if !self.check_ready() {
- return command;
- }
- // 取消、平掉所有
- self._close_all(&mut command);
- // 更新撤单队列
- self._update_in_cancel(&mut command);
- // 检查限频
- self._check_request_limit(&mut command);
- // 统计请求频率
- self._update_request_num(&mut command);
- }
- // debug!(?command);
- return command;
- }
- // 休眠时调用,全撤 不再下新订单了 防止影响check_position执行
- pub fn on_sleep(&mut self, trader_msg: &TraderMsg) -> OrderCommand {
- let mut command = OrderCommand::new();
- if self._update_data(trader_msg) {
- if !self.check_ready() {
- return command;
- }
- // 只是取消掉目标侧订单
- self._cancel_target_side_orders(&mut command);
- // 更新撤单队列
- self._update_in_cancel(&mut command);
- // 检查限频
- self._check_request_limit(&mut command);
- // 统计请求频率
- self._update_request_num(&mut command);
- }
- // debug!(?command);
- return command;
- }
- // 清空所有挂单和仓位保持休眠状态
- #[instrument(skip(self, command), level="TRACE")]
- pub fn _close_all(&self, command: &mut OrderCommand) {
- // 撤掉全部挂单
- let mut pd_amount = Decimal::ZERO;
- let mut pk_amount = Decimal::ZERO;
- // debug!(?self.local_orders);
- for client_id in self.local_orders.keys() {
- let order = self.local_orders.get(client_id).unwrap();
- // 命令生成
- let key = format!("Cancel{}", client_id);
- let value = vec![order.client_id.clone(), order.order_id.clone()];
- command.cancel.insert(key, value);
- // 统计部分
- if order.side == "pk".to_string() {
- pk_amount += order.amount;
- } else if order.side == "pd".to_string() {
- pd_amount += order.amount;
- }
- }
- // debug!(?pd_amount, ?pk_amount);
- // 批量挂单
- let need_close_long = self.pos.long_pos - pd_amount;
- let need_close_short = self.pos.short_pos - pk_amount;
- // debug!(?need_close_long, ?need_close_short);
- // 做多仓位平仓
- if need_close_long * self.mp > self._min_amount_value {
- let mut amount = need_close_long;
- // 现货要对数量精度进行限定处理
- if self.exchange.contains("spot") {
- amount = utils::fix_amount(amount, self.step_size);
- }
- let price = utils::fix_price(self.mp, self.tick_size);
- let client_id = utils::generate_client_id(Some(self.broker_id.clone()));
- let value = vec![
- amount.to_string(),
- "pd".to_string(),
- price.to_string(),
- client_id.to_string()
- ];
- command.limits_close.insert(client_id.clone(), value);
- // debug!(?self.pos.long_pos, ?self.mp, ?need_close_long, ?command)
- }
- // 做空仓位平仓
- if need_close_short * self.mp > self._min_amount_value {
- let mut amount = need_close_short;
- if self.exchange.contains("spot") {
- amount = utils::fix_amount(amount, self.step_size);
- }
- let price = utils::fix_price(self.mp, self.tick_size);
- let client_id = utils::generate_client_id(Some(self.broker_id.clone()));
- let value = vec![
- amount.to_string(),
- "pk".to_string(),
- price.to_string(),
- client_id.to_string()
- ];
- command.limits_close.insert(client_id.clone(), value);
- // debug!(?self.pos.short_pos, ?self.mp, ?need_close_short, ?command)
- }
- }
- // 检查是否完成准备,注意:原文是未准备完成返回true!!!!!!!!!!!!!!!!!!!
- pub fn check_ready(&mut self) -> bool {
- if self.is_ready {
- return true;
- }
- let pre_hot:i64 = 10 * 1000;
- if !self.mp.eq(&Decimal::ZERO) && self.local_time - self.local_start_time > pre_hot {
- self.is_ready = true;
- // debug!(?self.mp, ?self.local_time, ?self.local_start_time, ?pre_hot);
- info!("策略预热完毕,可以执行后续逻辑!")
- }
- return false;
- }
- // 接近整点时刻 不允许报单 防止下单bug
- pub fn check_allow_post_open(&self) -> bool {
- let local_time_second = self.local_time / 1000;
- let diff_time = local_time_second % (60 * 60);
- return diff_time > 30 && diff_time < 3570;
- }
- // 平仓订单处理命令
- #[instrument(skip(self, command), level="TRACE")]
- pub fn _post_close(&self, command: &mut OrderCommand) {
- // debug!(?command);
- let mut pd_amount = Decimal::ZERO;
- let mut pd_order_num = 0;
- let mut pk_amount = Decimal::ZERO;
- let mut pk_order_num = 0;
- // 各类价格
- let long_upper = self.close_dist[0];
- let long_lower = self.close_dist[1];
- let short_lower = self.close_dist[2];
- let short_upper = self.close_dist[3];
- // 获取当前挂单,如果超过挂单范围则取消当前平仓单
- for order_client_id in self.local_orders.keys() {
- let order = self.local_orders.get(order_client_id).unwrap();
- let key = format!("Cancel{}", (*order_client_id).clone());
- let value = vec![order.client_id.clone(), order.order_id.clone()];
- if order.side == "pk".to_string() {
- if order.price > long_upper || order.price < long_lower {
- command.cancel.insert(key.clone(), value.clone());
- }
- pk_amount += order.amount;
- pk_order_num += 1;
- }
- if order.side == "pd".to_string() {
- if order.price < short_lower || order.price > short_upper {
- command.cancel.insert(key.clone(), value.clone());
- }
- pd_amount += order.amount;
- pd_order_num += 1;
- }
- }
- // debug!(?command);
- // 判断是否需要全平
- let is_need_cancel_all_close =
- (pd_amount - self.pos.long_pos).abs() * self.mp > self._min_amount_value
- || (pk_amount - self.pos.short_pos).abs() * self.mp > self._min_amount_value;
- if is_need_cancel_all_close {
- for order_client_id in self.local_orders.keys() {
- let order = self.local_orders.get(order_client_id).unwrap();
- if order.side == "pk".to_string() || order.side == "pd".to_string() {
- let key = format!("Cancel{}", (*order_client_id).clone());
- let value = vec![order.client_id.clone(), order.order_id.clone()];
- command.cancel.insert(key.clone(), value.clone());
- }
- }
- }
- // debug!(?command);
- // 区分现货和期货
- if self.exchange.contains("spot") {
- // 平多价值大于最小交易价值,执行平多逻辑
- if self.pos.long_pos * self.mp > self._min_amount_value {
- if pd_order_num == 0 {
- let mut price = (short_lower + short_upper) * dec!(0.5);
- price = utils::clip(price, self.bp * dec!(0.9995), self.ap * dec!(1.03));
- price = utils::fix_price(price, self.tick_size);
- let mut amount = self.pos.long_pos;
- amount = utils::fix_amount(amount, self.step_size);
- if amount * price > self._min_amount_value {
- let order_client_id = utils::generate_client_id(Some(self.broker_id.clone()));
- let order = vec![
- amount.to_string(),
- "pd".to_string(),
- price.to_string(),
- order_client_id.clone()
- ];
- command.limits_close.insert(order_client_id, order.clone());
- // debug!(?command);
- }
- }
- }
- // 平空价值大于最小交易价值,执行平空逻辑
- if self.pos.short_pos > self._min_amount_value {
- if pk_order_num == 0 {
- let mut price = (long_upper + long_lower) * dec!(0.5);
- price = utils::clip(price, self.bp * dec!(0.97), self.ap * dec!(1.0005));
- price = utils::fix_price(price, self.tick_size);
- let mut amount = self.pos.short_pos;
- amount = utils::fix_amount(amount, self.step_size);
- if amount * price > self._min_amount_value {
- let order_client_id = utils::generate_client_id(Some(self.broker_id.clone()));
- let order = vec![
- amount.to_string(),
- "pk".to_string(),
- price.to_string(),
- order_client_id.clone()
- ];
- command.limits_close.insert(order_client_id, order.clone());
- // debug!(?command);
- }
- }
- }
- } else {
- if self.pos.long_pos > Decimal::ZERO {
- if pd_order_num == 0 {
- let mut price = (short_lower + short_upper) * dec!(0.5);
- price = utils::clip(price, self.bp * dec!(0.9995), self.ap * dec!(1.03));
- price = utils::fix_price(price, self.tick_size);
- let order_client_id = utils::generate_client_id(Some(self.broker_id.clone()));
- let order = vec![
- self.pos.long_pos.to_string(),
- "pd".to_string(),
- price.to_string(),
- order_client_id.clone()
- ];
- command.limits_close.insert(order_client_id, order.clone());
- // debug!(?command);
- }
- }
- if self.pos.short_pos > Decimal::ZERO {
- if pk_order_num == 0 {
- let mut price = (long_upper + long_lower) * dec!(0.5);
- price = utils::clip(price, self.bp * dec!(0.97), self.ap * dec!(1.0005));
- price = utils::fix_price(price, self.tick_size);
- let order_client_id = utils::generate_client_id(Some(self.broker_id.clone()));
- let order = vec![
- self.pos.short_pos.to_string(),
- "pk".to_string(),
- price.to_string(),
- order_client_id.clone()
- ];
- command.limits_close.insert(order_client_id, order.clone());
- // debug!(?command);
- }
- }
- }
- }
- // 生成取消订单的指令
- #[instrument(skip(self, command), level="TRACE")]
- pub fn _cancel_open(&self, command: &mut OrderCommand) {
- // debug!(?command);
- // 挂单范围
- let long_upper = self.open_dist[0];
- let long_lower = self.open_dist[1];
- let short_lower = self.open_dist[2];
- let short_upper = self.open_dist[3];
- for order_client_id in self.local_orders.keys() {
- let order = self.local_orders.get(order_client_id).unwrap();
- let key = format!("Cancel{}", (*order_client_id).clone());
- let value = vec![order.client_id.clone(), order.order_id.clone()];
- // 开多订单处理
- if order.side == "kd".to_string() {
- // 在价格范围内时不处理
- if order.price <= long_upper && order.price >= long_lower {
- continue
- }
- // debug!(?key, ?order.price, ?long_upper, ?long_lower);
- command.cancel.insert(key.clone(), value.clone());
- }
- // 开空订单处理
- if order.side == "kk".to_string() {
- // 在价格范围内时不处理
- if order.price >= short_lower && order.price <= short_upper {
- continue
- }
- // debug!(?key, ?order.price, ?short_lower, ?short_upper);
- command.cancel.insert(key.clone(), value.clone());
- }
- }
- }
- // 超时触发查单信号
- #[instrument(skip(self, command), level="TRACE")]
- pub fn _check_local_orders(&mut self, command: &mut OrderCommand) {
- // debug!(?command);
- // 超时检测
- if self.local_time - self._check_local_orders_time < self._check_local_orders_interval {
- return;
- }
- // 查单指令生成主逻辑
- for client_id in self.local_orders.keys() {
- let check_some = self.in_check.get(client_id);
- // 如果在查单队列中,不需要再添加
- if let Some(_) = check_some {
- continue;
- }
- let order = self.local_orders.get(client_id).unwrap();
- // 没有超过10s的订单,不需要检查
- if self.local_time - order.local_time < self._check_local_orders_interval {
- continue;
- }
- let key = format!("Check{}", client_id.clone());
- let value = vec![
- client_id.clone(),
- order.order_id.clone(),
- ];
- command.check.insert(key, value);
- self.in_check.insert(client_id.clone(), self.local_time);
- // debug!("查询订单:{:?}", client_id.clone());
- // debug!(?command);
- }
- // 维护查单队列
- self._release_in_check();
- // 更新查单时间
- self._check_local_orders_time = self.local_time;
- }
- // 开单指令生成逻辑
- #[instrument(skip(self, command), level="TRACE")]
- pub fn _post_open(&mut self, command: &mut OrderCommand) {
- // debug!(?command);
- // 开仓逻辑检测,主要是检测整点开仓逻辑
- if !self.check_allow_post_open() {
- return;
- }
- // 报单时延检测
- if self.local_time - self.post_open_time < self.post_open_interval {
- return;
- }
- // 报单时间更新
- self.post_open_time = self.local_time;
- // 挂单范围获取
- let long_upper = self.open_dist[0];
- let long_lower = self.open_dist[1];
- let short_lower = self.open_dist[2];
- let short_upper = self.open_dist[3];
- // 获取当前挂单价值
- let mut buy_price_list: Vec<Decimal> = vec![];
- let mut sell_price_list: Vec<Decimal> = vec![];
- let mut buy_value = Decimal::ZERO;
- let mut sell_value = Decimal::ZERO;
- for client_id in self.local_orders.keys() {
- let order = self.local_orders.get(client_id).unwrap();
- if order.side == "kd".to_string() {
- buy_price_list.push(order.price);
- buy_value += order.amount * order.price;
- }
- if order.side == "kk".to_string() {
- sell_price_list.push(order.price);
- sell_value += order.amount * order.price;
- }
- }
- // 计算可开价值
- let mut long_free_value = self.max_long_value - self.long_hold_value - buy_value;
- let mut short_free_value = self.max_short_value - self.short_hold_value - sell_value;
- // debug!(?long_free_value, ?short_free_value);
- // 现货要特殊处理
- if self.exchange.contains("spot") {
- let coin_value = self.coin * self.mp * self.lever_rate * self.adjust_lever_rate;
- let cash_value = self.cash * self.lever_rate * self.adjust_lever_rate;
- long_free_value = min(cash_value, self.max_long_value) - buy_value;
- short_free_value = min(coin_value, self.max_short_value) - sell_value;
- }
- // 一手开单价值计算
- let one_hand_long_value = dec!(0.99) * (self.max_long_value / self.grid);
- let one_hand_short_value = dec!(0.99) * (self.max_short_value / self.grid);
- // debug!(?self.post_side);
- // 挂多单
- if self.post_side >= 0 {
- // debug!(?buy_price_list);
- if buy_price_list.len() == 0 {
- let mut target_buy_price = (long_upper + long_lower) * dec!(0.5);
- target_buy_price = utils::clip(target_buy_price, self.bp * dec!(0.97), self.ap * dec!(1.0005));
- target_buy_price = utils::fix_price(target_buy_price, self.tick_size);
- let value = min(one_hand_long_value, long_free_value);
- let amount = utils::fix_amount(value / self.mp, self.step_size);
- let amount_value = amount * self.mp;
- // debug!(?one_hand_long_value, ?long_free_value, ?amount);
- // 下单价值不能太大,也不能太小
- if amount_value >= self._min_amount_value && amount_value <= long_free_value {
- let client_id = utils::generate_client_id(Some(self.broker_id.clone()));
- let order = vec![
- amount.to_string(),
- "kd".to_string(),
- target_buy_price.to_string(),
- client_id.clone(),
- ];
- // debug!(?order);
- command.limits_open.insert(client_id.clone(), order);
- }
- }
- }
- // 挂空单
- if self.post_side <= 0 {
- // debug!(?sell_price_list);
- if sell_price_list.len() == 0 {
- let mut target_sell_price = (short_lower + short_upper) * dec!(0.5);
- target_sell_price = utils::clip(target_sell_price, self.bp * dec!(0.9995), self.ap * dec!(1.03));
- target_sell_price = utils::fix_price(target_sell_price, self.tick_size);
- let value = min(one_hand_short_value, short_free_value);
- let amount = utils::fix_amount(value / self.mp, self.step_size);
- let amount_value = amount * self.mp;
- // 下单价值不能太大,也不能太小
- if amount_value >= self._min_amount_value && amount_value <= short_free_value {
- let client_id = utils::generate_client_id(Some(self.broker_id.clone()));
- let order = vec![
- amount.to_string(),
- "kk".to_string(),
- target_sell_price.to_string(),
- client_id.clone(),
- ];
- // debug!(?order);
- command.limits_open.insert(client_id.clone(), order);
- }
- }
- }
- }
- // 定时打印
- pub fn on_time_print(&mut self) {
- if self.local_time - self._print_time < self._print_interval {
- return;
- }
- // 记录上次打印时间
- self._print_time = self.local_time;
- if !self._is_print {
- return;
- }
- // 准备好了的话就不打印预热中了
- if self.is_ready {
- return;
- }
- info!("预热中");
- }
- // 在满足条件后,返回非空command,否则返回一个空的command。原文的onTime。
- pub fn on_time(&mut self, trader_msg: &TraderMsg) -> OrderCommand {
- self.on_time_print();
- let mut command = OrderCommand::new();
- // 更新逻辑数据出错时,不进行后面的逻辑处理
- if !self._update_data(trader_msg) {
- return command;
- }
- // 检查是否准备充分
- if !self.check_ready() {
- return command;
- }
- // 刷新多空双方持仓比例
- self._pos_rate();
- // 生成开仓、平仓等相关价格
- self.generate_dist();
- // 下单指令处理逻辑
- self._cancel_open(&mut command); // 撤单命令处理
- self._post_open(&mut command); // 限价单命令处理
- self._post_close(&mut command); // 平仓单命令处理
- self._check_local_orders(&mut command); // 固定时间检查超时订单
- self._update_in_cancel(&mut command); // 更新撤单队列,是一个filter
- self._check_request_limit(&mut command); // 限制频率,移除不合规则之订单,是一个filter
- self._refresh_request_limit(); // 刷新频率限制
- self._update_request_num(&mut command); // 统计刷新频率
- if command.limits_open.len() > 0 || command.limits_close.len() > 0{
- let time = chrono::Utc::now().timestamp_millis();
- let name = self.params.account_name.clone();
- // 参考卖价
- let ref_ap = self.ref_ap;
- // 参考买价
- let ref_bp = self.ref_bp;
- let limits_open = command.limits_open.clone();
- let limits_close = command.limits_close.clone();
- spawn(async move {
- let param_list = paras_limit_command(name.clone(), time.clone(), ref_ap.clone(), ref_bp.clone(), limits_open, limits_close);
- let param_json_obj = serde_json::to_string(¶m_list).unwrap();
- market_warehouse_request(param_json_obj).await;
- });
- }
- return command;
- }
- }
- async fn market_warehouse_request(body_params: String) {
- /****请求接口与 地址*/
- let url = "http://as.skyfffire.com:8848/basic/saveDealRecords";
- let client = Client::new();
- let req = client.post(url).header("auth", "43626546liangjiang")
- .header("Content-Type", "application/json").body(body_params.clone());
- match req.send().await {
- Ok(_) => {}
- Err(_) => {}
- };
- // if !response.status().is_success() {
- // error!("行情数据------仓库挂单数据存储失败--------!{}", response.status());
- // error!(body_params);
- // }
- }
- fn paras_limit_command (robot_name: String, time: i64, ref_ap: Decimal, ref_bp: Decimal, limits_open: HashMap<String, Vec<String>>, limits_close: HashMap<String, Vec<String>>) -> Vec<DealRecord>{
- let mut limits = HashMap::new();
- limits.extend(limits_open);
- limits.extend(limits_close);
- let mut list: Vec<DealRecord> = Vec::with_capacity(limits.len());
- for item in limits.keys() {
- let item_clone = item.clone();
- let value = limits[&item_clone].clone();
- let amount = Decimal::from_str(value.get(0).unwrap_or(&"0".to_string())).unwrap();
- let side = value.get(1).unwrap();
- let price = Decimal::from_str(value.get(2).unwrap_or(&"0".to_string())).unwrap();
- let mut ref_price = ref_ap;
- if "kd" == side {
- ref_price = ref_bp;
- }
- let deal_recode = DealRecord {
- refPrice: ref_price.to_string(),
- regPrice: price.to_string(),
- num: amount.to_string(),
- triggerTime: time,
- robotName: robot_name.clone(),
- side: side.to_string(),
- };
- list.push(deal_recode);
- }
- return list;
- }
- #[cfg(test)]
- mod tests {
- use rust_decimal::Decimal;
- use rust_decimal_macros::dec;
- use crate::model::{OrderInfo, TraderMsg};
- use global::params::Params;
- use crate::strategy::Strategy;
- #[test]
- fn on_time_test() {
- global::log_utils::init_log_with_debug();
- let params = Params::new("config.toml.gate").unwrap();
- let mut strategy = Strategy::new(¶ms, true);
- let mut trader_msg = TraderMsg::new();
- trader_msg.market.append(&mut vec![dec!(0.92), dec!(1.0), dec!(0.89), dec!(0.79), dec!(0.99), dec!(1.0), dec!(0.89), dec!(0.79), dec!(0.89), dec!(0.79), dec!(0.99), dec!(1.0), dec!(0.89), dec!(0.79)]);
- trader_msg.position.long_pos = dec!(100);
- trader_msg.position.long_avg = dec!(0.9);
- trader_msg.orders.insert("0001".to_string(), OrderInfo{
- symbol: "".to_string(),
- amount: Default::default(),
- side: "pd".to_string(),
- price: dec!(10),
- client_id: "0001".to_string(),
- filled_price: Default::default(),
- filled: Decimal::ZERO,
- order_id: "".to_string(),
- local_time: 0,
- create_time: 0,
- status: "".to_string(),
- fee: Default::default(),
- trace_stack: Default::default(),
- });
- trader_msg.cash = dec!(1000);
- trader_msg.coin = Decimal::ZERO;
- strategy.is_ready = true;
- strategy.equity = dec!(1000);
- strategy.lever_rate = Decimal::ONE;
- // debug!("{:?}", strategy.on_time(&trader_msg));
- }
- }
|