clear_core.rs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. use tokio::time::Instant;
  2. use std::collections::{BTreeMap, HashMap};
  3. use std::io::Error;
  4. use std::sync::Arc;
  5. use std::sync::atomic::{AtomicBool};
  6. use std::time::Duration;
  7. use chrono::{Utc};
  8. use reqwest::header::{CONTENT_TYPE, HeaderMap, HeaderValue};
  9. use rust_decimal::Decimal;
  10. use rust_decimal_macros::dec;
  11. use tokio::sync::mpsc::{Sender};
  12. use tokio::sync::{Mutex};
  13. use tokio::time::sleep;
  14. use tracing::{error, info, warn};
  15. use global::cci::CentralControlInfo;
  16. use global::clear_position_result::ClearPositionResult;
  17. use global::params::Params;
  18. use global::trace_stack::TraceStack;
  19. use standard::{Account, Market, Order, Platform, Position, PositionModeEnum, SpecialTicker};
  20. use standard::exchange::{Exchange};
  21. use standard::exchange::ExchangeEnum::{BinanceSwap, BitgetSwap, BybitSwap, CoinexSwap, GateSwap, HtxSwap, KucoinSwap};
  22. use crate::model::{LocalPosition, OrderInfo};
  23. use crate::predictor::Predictor;
  24. use crate::strategy::Strategy;
  25. use crate::utils;
  26. use crate::utils::clip;
  27. pub struct ClearCore {
  28. pub params: Params,
  29. // 启动时间
  30. pub start_time: i64,
  31. // 币对
  32. pub symbol: String,
  33. // 基础货币
  34. pub base: String,
  35. // 报价货币
  36. pub quote: String,
  37. //
  38. pub strategy: Strategy,
  39. // 本地挂单表
  40. pub local_orders: HashMap<String, OrderInfo>,
  41. // 本地订单缓存队列
  42. pub local_orders_backup: HashMap<String, OrderInfo>,
  43. // 本地订单缓存cid队列
  44. pub local_orders_backup_cid: Vec<String>,
  45. // 本地已处理cid缓存队列
  46. pub handled_orders_cid: Vec<String>,
  47. // 本地利润值
  48. pub local_profit: Decimal,
  49. // 本地U保证金
  50. pub local_cash: Decimal,
  51. // 本地币保证金
  52. pub local_coin: Decimal,
  53. // 仓位信息
  54. pub local_position: LocalPosition,
  55. // 仓位信息-来自订单
  56. pub local_position_by_orders: LocalPosition,
  57. //
  58. pub local_buy_amount: Decimal,
  59. pub local_sell_amount: Decimal,
  60. pub local_buy_value: Decimal,
  61. pub local_sell_value: Decimal,
  62. pub local_cancel_log: HashMap<String, i64>,
  63. pub interval: u64,
  64. pub exchange: String,
  65. pub exit_msg: String,
  66. // 仓位检查结果序列
  67. pub position_check_series: Vec<i8>,
  68. // 止损大小
  69. pub stop_loss: Decimal,
  70. // 资金使用率
  71. pub used_pct: Decimal,
  72. // 启停信号 0 表示运行 大于1开始倒计时 1时停机
  73. pub mode_signal: i8,
  74. // 交易盘口订单流更新时间
  75. pub trade_order_update_time: i64,
  76. // onTick触发时间记录
  77. pub on_tick_event_time: i64,
  78. // 盘口ticker信息
  79. pub tickers: HashMap<String, SpecialTicker>,
  80. // 盘口 depth信息
  81. pub depths: HashMap<String, Vec<Decimal>>,
  82. // 行情更新延迟监控(风控)
  83. pub market_update_time: HashMap<String, i64>,
  84. pub market_update_interval: HashMap<String, Decimal>,
  85. pub ref_num: i8,
  86. pub ref_name: Vec<String>,
  87. pub trade_name: String,
  88. pub ready: i8,
  89. pub predictor: Predictor,
  90. pub market: Market,
  91. pub platform_rest: Box<dyn Platform + Send + Sync>,
  92. // 市场最优买卖价
  93. pub max_buy_min_sell_cache: HashMap<String, Vec<Decimal>>,
  94. // 最近一次的depth信息
  95. pub local_depths: HashMap<String, Vec<Decimal>>,
  96. pub is_update: HashMap<String, bool>,
  97. pub running: Arc<AtomicBool>,
  98. pub hold_coin: Decimal,
  99. // 打印限频
  100. pub prev_log_ready_timestamp: i64,
  101. pub log_ready_log_interval: i64,
  102. // 中控
  103. pub cci_arc: Arc<Mutex<CentralControlInfo>>, // 中控信息汇集
  104. // 老版的trader_msg留下来的
  105. pub agg_market: Vec<Decimal>,
  106. pub ref_price: Vec<Vec<Decimal>>,
  107. pub predict: Decimal,
  108. }
  109. impl ClearCore {
  110. pub async fn new(exchange: String,
  111. params: Params,
  112. exchange_params: BTreeMap<String, String>,
  113. order_sender: Sender<Order>,
  114. error_sender: Sender<Error>,
  115. running: Arc<AtomicBool>,
  116. cci_arc: Arc<Mutex<CentralControlInfo>>) -> ClearCore {
  117. let symbol = params.pair.clone();
  118. let pairs: Vec<&str> = params.pair.split('_').collect();
  119. let mut core_obj = ClearCore {
  120. params: params.clone(),
  121. start_time: 0,
  122. symbol: symbol.clone(),
  123. base: pairs[0].to_string(),
  124. quote: pairs[1].to_string(),
  125. // 现货底仓
  126. hold_coin: clip(params.hold_coin, Decimal::ZERO, Decimal::ONE_HUNDRED * Decimal::ONE_HUNDRED),
  127. strategy: Strategy::new(&params, true),
  128. local_orders: Default::default(),
  129. local_orders_backup: Default::default(),
  130. local_orders_backup_cid: Default::default(),
  131. handled_orders_cid: Default::default(),
  132. local_profit: Default::default(),
  133. local_cash: Default::default(),
  134. local_coin: Default::default(),
  135. local_position: LocalPosition {
  136. long_pos: Default::default(),
  137. short_pos: Default::default(),
  138. long_avg: Default::default(),
  139. short_avg: Default::default(),
  140. },
  141. local_position_by_orders: LocalPosition {
  142. long_pos: Default::default(),
  143. short_pos: Default::default(),
  144. long_avg: Default::default(),
  145. short_avg: Default::default(),
  146. },
  147. local_buy_amount: Default::default(),
  148. local_sell_amount: Default::default(),
  149. local_buy_value: Default::default(),
  150. local_sell_value: Default::default(),
  151. local_cancel_log: Default::default(),
  152. interval: params.interval,
  153. exchange: params.exchange,
  154. exit_msg: "正常退出".to_string(),
  155. position_check_series: Default::default(),
  156. stop_loss: params.stop_loss,
  157. used_pct: dec!(0.95),
  158. mode_signal: 0,
  159. trade_order_update_time: Utc::now().timestamp_millis(),
  160. on_tick_event_time: Utc::now().timestamp_millis(),
  161. tickers: Default::default(),
  162. depths: Default::default(),
  163. market_update_time: Default::default(),
  164. market_update_interval: Default::default(),
  165. ref_num: params.ref_exchange.len() as i8,
  166. ref_name: Default::default(),
  167. trade_name: "".to_string(),
  168. ready: 0,
  169. predictor: Predictor {
  170. loop_count: 0,
  171. market_info_list: vec![],
  172. mid_price_list: vec![],
  173. ref_mid_price_per_exchange_per_frame: vec![],
  174. ref_exchange_length: 0,
  175. data_length_max: 0,
  176. alpha: vec![],
  177. gamma: Default::default(),
  178. avg_spread_list: vec![],
  179. },
  180. market: Market {
  181. symbol: symbol.clone(),
  182. base_asset: "".to_string(),
  183. quote_asset: "".to_string(),
  184. tick_size: Default::default(),
  185. price_precision: Default::default(),
  186. amount_precision: Default::default(),
  187. min_qty: Default::default(),
  188. max_qty: Default::default(),
  189. min_notional: Default::default(),
  190. max_notional: Default::default(),
  191. ct_val: Default::default(),
  192. amount_size: Default::default(),
  193. },
  194. platform_rest: match exchange.as_str() {
  195. "kucoin_usdt_swap" => {
  196. Exchange::new(KucoinSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
  197. }
  198. "gate_usdt_swap" => {
  199. Exchange::new(GateSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
  200. }
  201. // "gate_usdt_spot" => {
  202. // Exchange::new(GateSpot, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
  203. // }
  204. "binance_usdt_swap" => {
  205. Exchange::new(BinanceSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
  206. }
  207. // "binance_spot" => {
  208. // Exchange::new(BinanceSpot, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
  209. // }
  210. // "bitget_spot" => {
  211. // Exchange::new(BitgetSpot, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
  212. // }
  213. "bitget_usdt_swap" => {
  214. Exchange::new(BitgetSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
  215. }
  216. // "okex_usdt_swap" => {
  217. // Exchange::new(OkxSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
  218. // }
  219. "bybit_usdt_swap" => {
  220. Exchange::new(BybitSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
  221. }
  222. "coinex_usdt_swap" => {
  223. Exchange::new(CoinexSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
  224. }
  225. "htx_usdt_swap" => {
  226. Exchange::new(HtxSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
  227. }
  228. _ => {
  229. error!("203未找到对应的交易所rest枚举!");
  230. panic!("203未找到对应的交易所rest枚举!");
  231. }
  232. },
  233. max_buy_min_sell_cache: Default::default(),
  234. local_depths: Default::default(),
  235. is_update: Default::default(),
  236. running,
  237. prev_log_ready_timestamp: 0,
  238. log_ready_log_interval: 10 * 1000,
  239. cci_arc,
  240. agg_market: vec![],
  241. ref_price: vec![],
  242. predict: Default::default(),
  243. };
  244. for i in 0..=params.ref_exchange.len() - 1 {
  245. // 拼接不会消耗原字符串
  246. let tickers_key: String = format!("{}{}{}{}", params.ref_exchange[i], "@", params.ref_pair[i], "@ref");
  247. let ref_name_element = tickers_key.clone();
  248. let depths_key: String = tickers_key.clone();
  249. let market_update_time_key = tickers_key.clone();
  250. let market_update_interval_key = tickers_key.clone();
  251. let max_buy_min_sell_cache_key = tickers_key.clone();
  252. core_obj.tickers.insert(tickers_key, SpecialTicker::new());
  253. core_obj.ref_name.push(ref_name_element);
  254. core_obj.depths.insert(depths_key, Default::default());
  255. core_obj.market_update_time.insert(market_update_time_key, Default::default());
  256. core_obj.market_update_interval.insert(market_update_interval_key, Default::default());
  257. core_obj.max_buy_min_sell_cache.insert(max_buy_min_sell_cache_key, vec![Decimal::ZERO, Decimal::ZERO]);
  258. }
  259. let name = format!("{}{}{}", core_obj.exchange.clone(), "@", core_obj.symbol);
  260. let market_update_time_key = name.clone();
  261. let market_update_interval_key = name.clone();
  262. let tickers_key = name.clone();
  263. let depths_key = name.clone();
  264. let max_buy_min_sell_cache_key = name.clone();
  265. core_obj.trade_name = name;
  266. core_obj.market_update_time.insert(market_update_time_key, Default::default());
  267. core_obj.market_update_interval.insert(market_update_interval_key, Default::default());
  268. core_obj.tickers.insert(tickers_key, SpecialTicker::new());
  269. core_obj.depths.insert(depths_key, Default::default());
  270. core_obj.max_buy_min_sell_cache.insert(max_buy_min_sell_cache_key, vec![Decimal::ZERO, Decimal::ZERO]);
  271. // broker.newWs
  272. let mut price_alpha: Vec<Decimal> = Vec::new();
  273. for ref_pair_str in params.ref_pair {
  274. if params.pair.contains("1000") && !ref_pair_str.contains("1000") {
  275. price_alpha.push(dec!(1000.0));
  276. } else if !params.pair.contains("1000") && ref_pair_str.contains("1000") {
  277. price_alpha.push(dec!(0.001))
  278. } else {
  279. price_alpha.push(dec!(1.0));
  280. }
  281. }
  282. info!("价格系数:{:?}", price_alpha);
  283. core_obj.predictor = Predictor::new(core_obj.ref_name.len())
  284. .alpha(price_alpha)
  285. .gamma(params.gamma);
  286. return core_obj;
  287. }
  288. pub fn log_ready_status(&mut self, msg: String) {
  289. // 隔一会再打印未准备就绪的台词
  290. let now_timestamp = Utc::now().timestamp_millis();
  291. if now_timestamp - self.prev_log_ready_timestamp > self.log_ready_log_interval {
  292. self.prev_log_ready_timestamp = now_timestamp;
  293. info!("{}", msg);
  294. }
  295. }
  296. // #[instrument(skip(self, data), level="TRACE")]
  297. pub async fn update_position(&mut self, data: Vec<Position>) {
  298. if data.is_empty() {
  299. return;
  300. }
  301. let mut position = LocalPosition::new();
  302. for pos in &data {
  303. if pos.position_mode == PositionModeEnum::Long {
  304. position.long_pos = pos.amount;
  305. position.long_avg = pos.price;
  306. } else if pos.position_mode == PositionModeEnum::Short {
  307. position.short_pos = pos.amount.abs();
  308. position.short_avg = pos.price;
  309. }
  310. }
  311. // 更新仓位信息
  312. if position != self.local_position {
  313. info!("收到新的仓位推送, position: {:?}", data);
  314. info!("更新本地仓位:{:?}", position);
  315. self.local_position = position;
  316. }
  317. // 更新中控持仓相关的信息
  318. {
  319. let mut pos = self.local_position_by_orders.long_pos - self.local_position_by_orders.short_pos;
  320. if !self.exchange.contains("spot") {
  321. pos = self.local_position.long_pos - self.local_position.short_pos;
  322. }
  323. pos.rescale(8);
  324. let mut entry_price;
  325. if pos.gt(&Decimal::ZERO) {
  326. entry_price = self.local_position_by_orders.long_avg;
  327. } else {
  328. entry_price = self.local_position_by_orders.short_avg;
  329. }
  330. entry_price.rescale(8);
  331. let mut cci = self.cci_arc.lock().await;
  332. cci.pos = pos;
  333. cci.entry_price = entry_price;
  334. }
  335. }
  336. // #[instrument(skip(self), level="TRACE")]
  337. pub async fn get_exchange_info(&mut self) {
  338. self.market = self.platform_rest.get_self_market();
  339. info!(?self.market);
  340. }
  341. // #[instrument(skip(self, data), level="TRACE")]
  342. pub async fn update_equity(&mut self, data: Account) {
  343. /*
  344. 更新保证金信息
  345. 合约一直更新
  346. 现货只有当出现异常时更新
  347. */
  348. if self.exchange.contains("spot") {
  349. return;
  350. }
  351. self.local_cash = data.balance * self.used_pct;
  352. }
  353. // #[instrument(skip(self), level="TRACE")]
  354. pub async fn update_equity_rest_swap(&mut self) {
  355. match self.platform_rest.get_account().await {
  356. Ok(account) => {
  357. /*
  358. 更新保证金信息
  359. 合约一直更新
  360. 现货只有当出现异常时更新
  361. */
  362. self.local_cash = account.balance * self.used_pct
  363. }
  364. Err(e) => {
  365. info!("获取账户信息错误: {:?}", e);
  366. }
  367. }
  368. }
  369. pub async fn update_position_rest_swap(&mut self) {
  370. let position = self.platform_rest.get_position().await;
  371. match position {
  372. Ok(val) => {
  373. // info!("bybit_swap:定时获取的仓位信息");
  374. self.update_position(val).await;
  375. }
  376. Err(err) => {
  377. error!("bybit_swap:定时获取仓位信息错误!\nget_position:res_data={:?}", err);
  378. }
  379. }
  380. }
  381. // #[instrument(skip(self), level="TRACE")]
  382. pub async fn update_equity_rest_spot(&mut self) {
  383. match self.platform_rest.get_spot_account().await {
  384. Ok(mut val) => {
  385. // 如果返回的数组里没有交易货币,则补充交易货币
  386. if !val.iter().any(|a| a.coin.to_uppercase().eq(&self.base.to_uppercase())) {
  387. let mut base_coin_account = Account::new();
  388. base_coin_account.coin = self.base.to_uppercase();
  389. val.push(base_coin_account);
  390. }
  391. for account in val {
  392. // 交易货币
  393. if self.base.to_uppercase() == account.coin {
  394. self.local_coin = account.balance;
  395. }
  396. // 本位货币
  397. if self.quote.to_uppercase() == account.coin {
  398. self.local_cash = account.balance;
  399. }
  400. }
  401. }
  402. Err(err) => {
  403. error!("获取仓位信息异常: {}", err);
  404. }
  405. }
  406. }
  407. // #[instrument(skip(self, target_hold_coin), level="TRACE")]
  408. pub async fn check_position(&mut self) -> ClearPositionResult {
  409. let mut result = ClearPositionResult::new();
  410. info!("------------------------------------------------------------------------------------------------------------");
  411. info!("步骤一:检查挂单:");
  412. match self.platform_rest.cancel_orders_all().await {
  413. Ok(val) => {
  414. let length = val.len();
  415. result.clear_order_num = length.to_string();
  416. info!("已清空所有挂单({}条)", length);
  417. result.clear_order_str = format!("清空所有挂单:{:?}", val);
  418. for o in val {
  419. info!(" {:?}", o);
  420. }
  421. }
  422. Err(err) => {
  423. warn!("取消所有订单异常({}),启动备用方法。", err);
  424. match self.platform_rest.cancel_orders().await {
  425. Ok(val) => {
  426. let length = val.len();
  427. result.clear_order_num = length.to_string();
  428. result.clear_order_str = format!("清空所有挂单(备用):{:?}", val);
  429. info!("清空所有挂单({}条):{:?}", length, val);
  430. }
  431. Err(exc) => {
  432. result.clear_order_str = exc.to_string();
  433. result.clear_other_err = true;
  434. error!("清空当前币对订单异常: {}", exc);
  435. }
  436. }
  437. }
  438. }
  439. info!("挂单检查完毕。");
  440. info!("");
  441. info!("步骤二:检查仓位:");
  442. match self.platform_rest.get_positions().await {
  443. Ok(val) => {
  444. info!("检查仓位信息");
  445. result.clear_position_num = val.len().to_string();
  446. for position in val {
  447. if position.amount.eq(&Decimal::ZERO) {
  448. continue;
  449. }
  450. info!(" 仓位:{:?}", position);
  451. let price = Decimal::ZERO;
  452. let side;
  453. info!(?position);
  454. match position.position_mode {
  455. PositionModeEnum::Long => {
  456. // pd
  457. side = "pd";
  458. }
  459. PositionModeEnum::Short => {
  460. // pk
  461. side = "pk";
  462. }
  463. _ => {
  464. error!(" 仓位position_mode匹配失败,不做操作!");
  465. // 执行完当前币对 结束循环
  466. continue;
  467. }
  468. }
  469. // 发起清仓订单
  470. let mut ts = TraceStack::new(0, Instant::now());
  471. ts.on_before_send();
  472. // 市价单
  473. match self.platform_rest.take_order_symbol(position.symbol.clone(),
  474. Decimal::ONE,
  475. utils::generate_client_id(None).as_str(),
  476. side,
  477. price,
  478. position.amount.abs()).await {
  479. Ok(order) => {
  480. ts.on_after_send();
  481. info!(" {}仓位清除市价下单成功 {:?}, {}", position.symbol.clone(), order, ts.to_string());
  482. result.clear_position_str = format!("{} >仓位信息:{:?} 下单信息: {:?}",result.clear_position_str, position, order);
  483. // 执行完当前币对 结束循环
  484. continue;
  485. }
  486. Err(error) => {
  487. // ts.on_after_send();
  488. error!(" {}仓位清除市价下单异常 {}, {}", position.symbol.clone(), error, ts.to_string());
  489. result.clear_other_str = format!("{} >仓位信息:{:?} 下单异常信息: {:?}",result.clear_other_str, position, error);
  490. // 执行完当前币对 结束循环
  491. continue;
  492. }
  493. };
  494. }
  495. }
  496. Err(error) => {
  497. result.clear_other_err = true;
  498. result.clear_position_str = format!("获取仓位异常 {}", error);
  499. error!("获取仓位信息异常: {}", error);
  500. }
  501. }
  502. info!("------------------------------------------------------------------------------------------------------------");
  503. info!("");
  504. return result;
  505. }
  506. // #[instrument(skip(self), level="TRACE")]
  507. pub async fn exit(&mut self, r_id: String) -> bool {
  508. info!("-------------------------启动退出流程({})----------------------------", self.exit_msg);
  509. info!("");
  510. let mut result = self.check_position().await;
  511. // 设置机器人id
  512. result.r_id = r_id;
  513. info!("清仓程序结果 {:?}", result);
  514. // 判断是否有清仓,是否有异常
  515. if result.clear_position_num != "0" || result.clear_order_num != "0" || result.clear_other_err{
  516. info!("上报了清仓信息!!!");
  517. send_clear_msg_request(&result).await;
  518. // 上报清仓日志
  519. }
  520. info!("订单、仓位清除完毕,为避免api失效导致遗漏仓位,建议人工复查。");
  521. info!("停机原因:{}。", self.exit_msg);
  522. return true;
  523. }
  524. // #[instrument(skip(self), level="TRACE")]
  525. pub async fn before_trade(&mut self) -> bool {
  526. sleep(Duration::from_secs(1)).await;
  527. // 获取市场信息
  528. self.get_exchange_info().await;
  529. // 获取价格信息
  530. let ticker = self.platform_rest.get_ticker().await.expect("获取价格信息异常!");
  531. info!(?ticker);
  532. let mp = (ticker.buy + ticker.sell) / Decimal::TWO;
  533. // 获取账户信息
  534. if self.exchange.contains("spot") {
  535. self.update_equity_rest_spot().await;
  536. } else {
  537. self.update_equity_rest_swap().await;
  538. }
  539. // 更新中控账户相关信息
  540. {
  541. let mut now_balance = self.local_cash / self.used_pct;
  542. now_balance.rescale(4);
  543. let mut cci = self.cci_arc.lock().await;
  544. cci.now_balance = now_balance;
  545. }
  546. // 初始资金
  547. let start_cash = self.local_cash.clone();
  548. let start_coin = self.local_coin.clone();
  549. if start_cash.is_zero() && start_coin.is_zero() {
  550. self.exit_msg = format!("{}{}{}{}", "初始余额为零 cash: ", start_cash, " coin: ", start_coin);
  551. }
  552. info!("初始cash: {start_cash} 初始coin: {start_coin}");
  553. // 初始化策略基础信息
  554. if mp <= Decimal::ZERO {
  555. self.exit_msg = format!("{}{}", "初始价格获取错误: ", mp);
  556. return false;
  557. } else {
  558. info!("初始价格为 {}", mp);
  559. }
  560. self.strategy.mp = mp.clone();
  561. self.strategy.start_cash = start_cash.clone();
  562. self.strategy.start_coin = start_coin.clone();
  563. self.strategy.start_equity = start_cash + start_coin * mp;
  564. self.strategy.max_equity = self.strategy.start_equity.clone();
  565. self.strategy.equity = self.strategy.start_equity.clone();
  566. self.strategy.total_amount = self.strategy.equity * self.strategy.lever_rate / self.strategy.mp;
  567. // 获取数量精度
  568. self.strategy.step_size = self.market.amount_size.clone();
  569. if self.strategy.step_size > Decimal::ONE {
  570. self.strategy.step_size = self.strategy.step_size.trunc();
  571. }
  572. // 获取价格精度
  573. self.strategy.tick_size = self.market.tick_size.clone();
  574. if self.strategy.tick_size > Decimal::ONE {
  575. self.strategy.tick_size = self.strategy.tick_size.trunc();
  576. }
  577. if self.strategy.step_size.is_zero() || self.strategy.tick_size.is_zero() {
  578. self.exit_msg = format!("{}{}{}{}", "交易精度未正常获取 step_size: ", self.strategy.step_size, " tick_size:", self.strategy.tick_size);
  579. return false;
  580. } else {
  581. info!("数量精度 {}", self.strategy.step_size);
  582. info!("价格精度 {}", self.strategy.tick_size);
  583. }
  584. // 初始化调度器
  585. self.local_cash = start_cash;
  586. self.local_coin = start_coin;
  587. // 买入平台币
  588. if self.exchange.contains("spot") { // 现货
  589. }
  590. // 清空挂单和仓位
  591. return true;
  592. }
  593. }
  594. // 清仓消息上报中控
  595. pub async fn send_clear_msg_request(body_params: &ClearPositionResult) {
  596. // 创建客户端
  597. let client = reqwest::Client::new();
  598. // 创建请求头
  599. let mut headers = HeaderMap::new();
  600. headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
  601. headers.insert("report-token", HeaderValue::from_static("r7T$8gBV!f&L@E2+"));
  602. headers.insert("auth", HeaderValue::from_static("4L"));
  603. let body = serde_json::to_string(&body_params).unwrap();
  604. // 发送 POST 请求
  605. let res = client
  606. .post("https://t4lapi.skyfffire.com/api/report/searchPositions")
  607. .body(body)
  608. .headers(headers)
  609. .send()
  610. .await;
  611. match res {
  612. Ok(response) => {
  613. let status = response.status();
  614. let response_text = response.text().await.unwrap_or("获取请求的响应文本异常".to_string());
  615. // 检查响应状态并读取响应体
  616. if status.is_success() {
  617. info!("清仓结果上报中控,请求成功,响应文本: {}", response_text);
  618. } else {
  619. println!("清仓结果上报中控,请求失败: 响应异常码 {},响应文本 {}", status, response_text);
  620. }
  621. },
  622. Err(e) => {
  623. error!("清仓结果上报中控,请求发送失败,异常:{}", e)
  624. }
  625. }
  626. }