Преглед изворни кода

hellor

结构体解析 和 深度回调。下次继续完善: _update_depth深度回调中的 追踪盘口情况下的逻辑
JiahengHe пре 2 година
родитељ
комит
8a0fb14426
6 измењених фајлова са 414 додато и 2 уклоњено
  1. 1 0
      standard/src/lib.rs
  2. 23 0
      strategy/config.toml
  3. 9 2
      strategy/src/main.rs
  4. 55 0
      strategy/src/model.rs
  5. 75 0
      strategy/src/params.rs
  6. 251 0
      strategy/src/quant.rs

+ 1 - 0
standard/src/lib.rs

@@ -100,6 +100,7 @@ pub struct Order {
 /// - `buy(Decimal)`: 买一价
 /// - `last(Decimal)`: 最后成交价
 /// - `volume(Decimal)`: 最近成交量
+#[derive(Debug)]
 pub struct Ticker {
     pub time: i64,
     pub high: Decimal,

+ 23 - 0
strategy/config.toml

@@ -0,0 +1,23 @@
+broker_id = ""
+account_name = "test_account_001"
+access_key = "B5261D7FB987478FA47E14F00C4A653B"
+secret_key = "CAF69F5A23DE0EA32B7B15777AF47609C61B1EB17E5AC203"
+pass_key = "21314123"
+exchange = "coinex_usdt_swap"
+pair = "rose_usdt"
+open = 0.001
+close = 0.0002
+lever_rate = 1.0
+interval = 0.1
+ref_exchange = ["binance_usdt_swap"]
+ref_pair = ["rose_usdt"]
+used_pct = 0.9
+index = 0
+save = 0
+hold_coin = 0.0
+log = 1
+stop_loss = 0.02
+gamma = 0.999
+grid = 1
+place_order_limit = 0
+colo = 0

+ 9 - 2
strategy/src/main.rs

@@ -1,3 +1,10 @@
-fn main() {
-    println!("Hello, world!");
+
+mod params;
+mod quant;
+mod model;
+mod utils;
+
+#[tokio::main]
+async fn main() {
+  println!("hello world!");
 }

+ 55 - 0
strategy/src/model.rs

@@ -0,0 +1,55 @@
+use std::collections::{BTreeMap};
+use rust_decimal::Decimal;
+use rust_decimal_macros::dec;
+#[derive(Debug)]
+pub struct Position{
+    // 做多仓位
+    pub long_pos: Decimal,
+    // 做空仓位
+    pub short_pos: Decimal,
+    //
+    pub long_avg: Decimal,
+    //
+    pub short_avg: Decimal
+}
+
+impl Position {
+    pub fn new() -> Position {
+        Position{
+            long_pos: dec!(0),
+            short_pos: dec!(0),
+            long_avg: dec!(0),
+            short_avg: dec!(0),
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct TraderMsg{
+    pub position: Position,
+    pub cash: Decimal,
+    pub coin: Decimal,
+    pub orders: BTreeMap<String, BTreeMap<String, String>>,
+    pub ref_price: Decimal,
+    pub market: Vec<Decimal>,
+    pub predict: Decimal
+}
+
+impl TraderMsg {
+    pub fn new() -> TraderMsg {
+        TraderMsg{
+            position: Position {
+                long_pos: Default::default(),
+                short_pos: Default::default(),
+                long_avg: Default::default(),
+                short_avg: Default::default(),
+            },
+            cash: Default::default(),
+            coin: Default::default(),
+            orders: Default::default(),
+            ref_price: Default::default(),
+            market: vec![],
+            predict: Default::default(),
+        }
+    }
+}

+ 75 - 0
strategy/src/params.rs

@@ -0,0 +1,75 @@
+use std::fs::File;
+use std::io::Read;
+use rust_decimal::Decimal;
+use toml::from_str;
+use serde_derive::Deserialize;
+
+
+#[derive(Debug, Deserialize, Clone)]
+pub struct Params {
+    // 经纪商id
+    pub broker_id: String,
+    // 账号昵称
+    pub account_name: String,
+    // ak
+    pub access_key: String,
+    // sk
+    pub secret_key: String,
+    // pk
+    pub pass_key: String,
+    // 交易盘口
+    pub exchange: String,
+    // 交易币对
+    pub pair: String,
+    // 开仓
+    pub open: Decimal,
+    // 平仓
+    pub close: Decimal,
+    // 杠杆大小
+    pub lever_rate: Decimal,
+
+    pub interval: Decimal,
+    // 参考盘口
+    pub ref_exchange: Vec<String>,
+    // 参考币种
+    pub ref_pair: Vec<String>,
+    // 账户资金使用比例
+    pub used_pct: Decimal,
+    // 默认第n参考盘口
+    pub index: i8,
+    pub hold_coin: Decimal,
+    // 止损比例 默认0.02  0.02 = 2%
+    pub stop_loss: Decimal,
+    // 平滑系数 默认0.999
+    pub gamma: Decimal,
+    // 分批建仓功能 小资金建议1 大资金建议3 默认 1
+    pub grid: i8,
+    // 允许的每秒下单次数
+    pub place_order_limit: i8,
+    // 是否启用colocation技术, 1开启,0关闭 默认0
+    pub colo: i8
+}
+
+impl Params {
+    pub fn new(file_path: &str) -> Result<Params, Box<dyn std::error::Error>> {
+        // 打开文件并读取内容
+        let mut file = File::open(file_path)?;
+        let mut contents = String::new();
+        file.read_to_string(&mut contents)?;
+
+        // 解析 TOML 数据到 Params 结构体
+        let params: Params = from_str(&contents)?;
+
+        Ok(params)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::params::Params;
+    #[tokio::test]
+    async fn test_new_exchange() {
+        let _params = Params::new("config.toml").unwrap();
+        println!("params:access_key:{},secret_key:{},pass_key:{}", _params.access_key, _params.secret_key, _params.pass_key);
+    }
+}

+ 251 - 0
strategy/src/quant.rs

@@ -0,0 +1,251 @@
+use std::collections::{HashMap};
+use chrono::{Timelike, Utc};
+use rust_decimal::Decimal;
+use rust_decimal_macros::dec;
+use standard::{Ticker};
+use crate::model::{Position, TraderMsg};
+use crate::params::Params;
+use crate::utils::{clip, LENGTH};
+
+#[derive(Debug)]
+pub struct Quant {
+    // 启动时间
+    pub start_time: i64,
+    // 币对
+    pub symbol: String,
+    // 基础货币
+    pub base: String,
+    // 报价货币
+    pub quote: String,
+    // 现货底仓
+    pub hold_coin: Decimal,
+    // 本地挂单表
+    pub local_orders: HashMap<String, HashMap<String, String>>,
+    // 本地订单缓存队列
+    pub local_orders_backup: HashMap<String, HashMap<String, String>>,
+    // 本地订单缓存cid队列
+    pub local_orders_backup_cid: Vec<String>,
+    // 本地已处理cid缓存队列
+    pub handled_orders_cid: Vec<String>,
+    // 本地利润值
+    pub local_profit: Decimal,
+    // 本地U保证金
+    pub local_cash: Decimal,
+    // 本地币保证金
+    pub local_coin: Decimal,
+    // 仓位信息
+    pub local_position: Position,
+    // 仓位信息-自订单
+    pub local_position_by_orders: Position,
+    //
+    pub local_buy_amount: Decimal,
+    pub local_sell_amount: Decimal,
+    pub local_buy_value: Decimal,
+    pub local_sell_value: Decimal,
+    pub local_cancel_log: HashMap<String, i64>,
+    pub interval: Decimal,
+    pub exchange: String,
+    pub trade_msg: TraderMsg,
+    pub exit_msg: String,
+    // 仓位检查结果序列
+    pub position_check_series: Vec<i8>,
+    // 止损大小
+    pub stop_loss: Decimal,
+    // 资金使用率
+    pub used_pct: Decimal,
+    // 启停信号 0 表示运行 大于1开始倒计时 1时停机
+    pub mode_signal: i8,
+    // 交易盘口订单流更新时间
+    pub trade_order_update_time: u32,
+    // onTick触发时间记录
+    pub on_tick_event_time: u32,
+    // 盘口ticker信息
+    pub tickers: HashMap<String, Ticker>,
+    // 盘口 depth信息
+    pub depths: HashMap<String, Vec<Decimal>>,
+    // 行情更新延迟监控(风控)
+    pub market_update_time: HashMap<String, u32>,
+    pub market_update_interval: HashMap<String, Decimal>,
+    pub ref_num: i8,
+    pub ref_name: Vec<String>,
+    pub trade_name: String,
+    pub ready: i8
+}
+
+struct MarketData{
+    data: Vec<Decimal>,
+    name: String
+}
+
+impl Quant {
+    pub fn new(params: Params) -> Quant{
+        let symbol = params.pair.clone();
+        let pairs: Vec<&str> = params.pair.split('_').collect();
+        let mut quant_obj = Quant {
+           start_time: 0,
+           symbol: symbol,
+           base: pairs[0].to_string(),
+           quote: pairs[1].to_string(),
+           hold_coin: clip(params.hold_coin, dec!(0.0), dec!(10000.0)),
+           local_orders: Default::default(),
+           local_orders_backup: Default::default(),
+           local_orders_backup_cid: vec![],
+           handled_orders_cid: vec![],
+           local_profit: Default::default(),
+           local_cash: Default::default(),
+           local_coin: Default::default(),
+           local_position: Position{
+               long_pos: Default::default(),
+               short_pos: Default::default(),
+               long_avg: Default::default(),
+               short_avg: Default::default(),
+           },
+           local_position_by_orders: Position{
+               long_pos: Default::default(),
+               short_pos: Default::default(),
+               long_avg: Default::default(),
+               short_avg: Default::default(),
+           },
+           local_buy_amount: Default::default(),
+           local_sell_amount: Default::default(),
+           local_buy_value: Default::default(),
+           local_sell_value: Default::default(),
+           local_cancel_log: Default::default(),
+           interval: params.interval,
+           exchange: params.exchange,
+           trade_msg: TraderMsg::new(),
+           exit_msg: "正常退出".to_string(),
+           position_check_series: vec![],
+           stop_loss: params.stop_loss,
+           used_pct: params.used_pct,
+           mode_signal: 0,
+           trade_order_update_time: Utc::now().nanosecond(),
+           on_tick_event_time: Utc::now().nanosecond(),
+           tickers: Default::default(),
+           depths: Default::default(),
+           market_update_time: Default::default(),
+           market_update_interval: Default::default(),
+           ref_num: params.ref_exchange.len() as i8,
+           ref_name: Default::default(),
+           trade_name: "".to_string(),
+           ready: 0
+        };
+        for i in 0..=params.ref_exchange.len()-1 {
+            // 拼接不会消耗原字符串
+            let tickers_key: String = format!("{}{}{}{}", params.ref_exchange[i], "@" , params.ref_pair[i], "@ref");
+            let ref_name_element = tickers_key.clone();
+            let depths_key: String = tickers_key.clone();
+            let market_update_time_key = tickers_key.clone();
+            let market_update_interval_key = tickers_key.clone();
+
+            quant_obj.tickers.insert(tickers_key, Ticker {
+                time: 0,
+                high: Default::default(),
+                low: Default::default(),
+                sell: Default::default(),
+                buy: Default::default(),
+                last: Default::default(),
+                volume: Default::default(),
+            });
+            quant_obj.ref_name.push(ref_name_element);
+            quant_obj.depths.insert(depths_key, Vec::new());
+            quant_obj.market_update_time.insert(market_update_time_key, 0);
+            quant_obj.market_update_interval.insert(market_update_interval_key, dec!(0));
+        }
+        return quant_obj;
+    }
+
+    // 检测初始数据是否齐全
+    pub fn check_ready(mut self){
+        // 检查 ticker 行情
+        for i in &self.ref_name{
+            if self.tickers.is_empty() || !self.tickers.contains_key(i) {
+                println!("参考盘口ticker未准备好");
+                return;
+            } else {
+                if self.tickers.get(i).unwrap().buy == dec!(0) || self.tickers.get(i).unwrap().sell == dec!(0){
+                    println!("参考盘口ticker未准备好");
+                    return;
+                }
+            }
+        }
+        if self.tickers.contains_key(&self.trade_name){
+            if self.tickers.get(&self.trade_name).unwrap().buy == dec!(0) || self.tickers.get(&self.trade_name).unwrap().sell == dec!(0)  {
+                println!("参考盘口ticker未准备好");
+                return;
+            }
+        } else {
+            println!("交易盘口ticker未准备好");
+            return;
+        }
+        // 检查 market 行情
+        let all_market:Vec<Decimal> = get_all_market_data();
+        if all_market.len() != LENGTH*(1usize+self.ref_num as usize){
+            println!("聚合行情未准备好");
+            return;
+        } else {
+            println!("聚合行情准备就绪");
+            self.trade_msg.market = all_market;
+            //
+            // TODO: 模型计算 (self.Predictor.onTime(all_market))
+            //
+        }
+        self.ready = 1
+    }
+
+    pub fn _update_depth(&mut self){
+        // 要从回调传入的深度信息中获取data.name
+        let name = "".to_string();
+        let market_update_interval_key = name.clone();
+        let market_update_time_key = name.clone();
+        let depths1_key = name.clone();
+        let depths2_key = name.clone();
+
+        let now_time = Utc::now().nanosecond();
+        if self.market_update_time.contains_key(&name) && *self.market_update_time.get(&name).unwrap() != 0u32{
+            let interval = Decimal::from(now_time - self.market_update_time.get(&name).unwrap());
+            if *self.market_update_interval.get(&name).unwrap() == dec!(0){
+                self.market_update_interval.insert(market_update_interval_key, interval);
+            }else{
+                let value = self.market_update_interval.get(&name).unwrap();
+                self.market_update_interval.insert(market_update_interval_key, value*dec!(0.999) + interval*dec!(0.001));
+            }
+        }
+        self.market_update_time.insert(market_update_time_key, now_time);
+        // 初始化depths
+        if self.depths.get(&name).unwrap().is_empty() {
+            // 要从回调传入的深度信息中获取data.data
+            self.depths.insert(depths1_key, vec![]);
+        }
+        // 判断是否需要触发ondepth
+        // 是否是交易盘口
+        if name == self.trade_name{
+            // 更新depths
+            self.depths.insert(depths2_key, vec![]);
+            // 允许交易
+            if self.mode_signal == 0 && self.ready == 1 {
+                // TODO: 聚合行情处理 self.on_agg_market()
+            }
+        } else if name == self.ref_name[self.strategy.ref_index] { // 判断是否为当前跟踪的盘口
+            // 判断是否需要触发ontick 对行情进行过滤
+            // 过滤条件 价格变化很大 时间间隔很长
+
+        }
+    }
+}
+// 获取深度信息
+pub fn get_all_market_data() -> Vec<Decimal>{
+    return Vec::new();
+}
+#[cfg(test)]
+mod tests {
+    use crate::params::Params;
+    use crate::quant::Quant;
+
+    #[tokio::test]
+    async fn test_new_exchange() {
+        let _params = Params::new("config.toml").unwrap();
+        let quant: Quant = Quant::new(_params);
+        println!("属性:{:?}", quant);
+    }
+}