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, // 撤单队列 pub cancel_wait_interval: i64, // 取消等待时延 pub in_check: HashMap, // 查单队列 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, // pub maker_mode: String, // pub local_orders: HashMap, // 本地订单 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, // 开仓相关价格 pub close_dist: Vec, // 平仓相关价格 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> = 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 = vec![]; let mut sell_price_list: Vec = 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>, limits_close: HashMap>) -> Vec{ let mut limits = HashMap::new(); limits.extend(limits_open); limits.extend(limits_close); let mut list: Vec = 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)); } }