Explorar el Código

Merge remote-tracking branch 'origin/master'

gepangpang hace 2 años
padre
commit
5c490a1250
Se han modificado 5 ficheros con 215 adiciones y 47 borrados
  1. 49 0
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 15 0
      README.md
  4. 143 46
      src/as_libs.rs
  5. 7 1
      src/exchange_libs.rs

+ 49 - 0
Cargo.lock

@@ -65,6 +65,7 @@ name = "as-market-binance-okx-spot"
 version = "0.1.0"
 dependencies = [
  "chrono",
+ "ndarray",
  "reqwest",
  "rust_decimal",
  "rust_decimal_macros",
@@ -579,6 +580,16 @@ version = "0.4.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
 
+[[package]]
+name = "matrixmultiply"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77"
+dependencies = [
+ "autocfg",
+ "rawpointer",
+]
+
 [[package]]
 name = "memchr"
 version = "2.5.0"
@@ -629,6 +640,38 @@ dependencies = [
  "tempfile",
 ]
 
+[[package]]
+name = "ndarray"
+version = "0.15.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32"
+dependencies = [
+ "matrixmultiply",
+ "num-complex",
+ "num-integer",
+ "num-traits",
+ "rawpointer",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
 [[package]]
 name = "num-traits"
 version = "0.2.16"
@@ -810,6 +853,12 @@ dependencies = [
  "getrandom",
 ]
 
+[[package]]
+name = "rawpointer"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
+
 [[package]]
 name = "redox_syscall"
 version = "0.3.5"

+ 1 - 0
Cargo.toml

@@ -13,3 +13,4 @@ chrono = "0.4.26"
 serde = "1.0.183"
 serde_derive = "1.0.183"
 serde_json = "1.0.104"
+ndarray = "0.15"

+ 15 - 0
README.md

@@ -0,0 +1,15 @@
+## 项目结构解析
+### 1. main.rs
+    这个应该不用介绍,就是做市程序入口
+### 2. as_libs.rs
+    AS套利模型的相关库
+### 3. exchange_libs.rs
+    交易所对接相关库
+### 4. exchange_middle_ware.rs
+    交易所中间键(方便其他模块对接)
+
+## 其他问题
+### 1. 关于库存的问题
+    我们的目的是维持0库存(库存目标通过公式优化)
+### 2. 运行方式
+    clone到本地/服务器之后,直接编译即可运行(需要配置)。

+ 143 - 46
src/as_libs.rs

@@ -1,32 +1,32 @@
+use std::num::FpCategory::Nan;
 use crate::exchange_middle_ware::{Depth, Record};
 
 // 获取买一卖一价差(spread)、中间价
-pub fn get_spread(depth: Depth) -> (f64, f64, f64, f64) {
-    return (0f64, 0f64, 0f64, 0f64);
-}
-
-// 方向判断函数
-pub fn get_direction(records: Vec<Record>) -> String {
-    // // 遍历列表中的每一条记录
-    // for record in records {
-    //     println!("Time: {}, Open: {}, High: {}, Low: {}, Close: {}, Volume: {}",
-    //              record.time, record.open, record.high, record.low, record.close, record.volume);
-    // }
+pub fn get_spread(depth: &Depth) -> (f64, f64, f64, f64) {
+    // 定义一个乘法系数,主要是防止f64精度丢失问题
+    let mul = 1e6;
 
-    let mut dir = "long";
+    let ask = depth.asks[0].price;
+    let bid = depth.bids[0].price;
+    let spread = (ask * mul - bid * mul) / mul;
+    let price_diff = (ask * mul + bid * mul) / (2f64 * mul);
 
-    return dir.to_string();
+    return (spread, price_diff, ask, bid);
 }
 
 // 计算最近N根K线的收盘价的标准差
-pub fn std_n_by_records(records: Vec<Record>, n: i8) -> Vec<f64> {
-    let mut rst = Vec::new();
+pub fn std_n_by_records(records: &Vec<Record>, n: usize) -> f64 {
+    let close_list: Vec<_> = records.iter().rev().take(n).map(|r| r.close).collect();
 
-    for i in 0..n {
-        rst.push(i as f64)
-    }
+    let count = close_list.len();
 
-    return rst;
+    let mean = close_list.iter().sum::<f64>() / (count as f64);
+    let variance = close_list.iter().map(|&value| {
+        let diff = mean - value;
+        diff * diff
+    }).sum::<f64>() / count as f64;
+
+    return variance.sqrt();
 }
 
 // 计算gamma值
@@ -38,7 +38,7 @@ pub fn calc_gamma(max_spread: f64, q: f64, std: f64) -> f64 {
 }
 
 // 计算价格偏差范围(加权平均值)
-pub fn calc_deviation_range(max_ira: f64, spread_list: Vec<f64>, ira: f64) -> f64 {
+pub fn calc_deviation_range(max_ira: f64, spread_list: &Vec<f64>, ira: f64) -> f64 {
     let max_spread = spread_list.iter().cloned().fold(f64::NAN, f64::max);
     let min_spread = spread_list.iter().cloned().fold(f64::NAN, f64::min);
 
@@ -75,35 +75,132 @@ pub fn calc_theta(gamma: f64, std: f64, kappa: f64, ira: f64) -> f64 {
     return (a + b) / 2f64;
 }
 
+// 给定ira、当前库存、最大库存、买入价格、下单数量小数位数,计算合理下单数量
+// 下单数量要与ira(风险系数)、quantity(库存)成反比
+pub fn calc_order_amount(ira_max: f64, ira: f64, quantity: f64, quantity_max: f64, bid_price: f64, amount_decimal_places: usize) -> f64 {
+    let eta = (ira_max / (ira + 1.0)) / (quantity * 2);
+    let order_value = (-quantity_max * eta).abs();
+    let order_amount = order_value / bid_price;
+
+    return truncate_decimal_places(order_amount, amount_decimal_places);
+}
+
+// 保留指定位数的小数
+pub fn truncate_decimal_places(num: f64, decimal_places: usize) -> f64 {
+    let multiplier = 10f64.powi(decimal_places as i32);
+    (num * multiplier).trunc() / multiplier
+}
+
+// 单元测试集
 #[cfg(test)]
 mod tests {
+    use crate::exchange_middle_ware::{get_binance_depth, get_binance_klines};
     use super::*;
 
     #[test]
-    fn test_direction() {
-        // 创建一个空的 Record 列表
-        let mut records = Vec::new();
-
-        // // 向列表中添加一条记录
-        // records.push(Record {
-        //     time: 1,
-        //     open: 100.0,
-        //     high: 200.0,
-        //     low: 50.0,
-        //     close: 150.0,
-        //     volume: 5000.0,
-        // });
-        //
-        // // 向列表中添加另一条记录
-        // records.push(Record {
-        //     time: 2,
-        //     open: 150.0,
-        //     high: 250.0,
-        //     low: 100.0,
-        //     close: 200.0,
-        //     volume: 7000.0,
-        // });
-
-        println!("{}", get_direction(records));
+    fn test_get_spread() {
+        let depth = get_binance_depth("BTC_USDT", "100");
+        let ask = depth.asks[0].price;
+        let bid = depth.bids[0].price;
+
+        println!("ask={}, bid={}", ask, bid);
+        println!("{:?}", get_spread(&depth))
+    }
+
+    #[test]
+    fn test_std_n_by_records() {
+        let records = vec![
+            Record{
+            time: 1567736576000,
+            open: 1000.0,
+            high: 1500.0,
+            low: 900.9,
+            close: 1200.9,
+            volume: 1000000.0,
+        }, Record{
+            time: 1567736576000,
+            open: 1000.0,
+            high: 1500.0,
+            low: 900.9,
+            close: 1219.9,
+            volume: 1000000.0,
+        }, Record{
+            time: 1567736576000,
+            open: 1000.0,
+            high: 1500.0,
+            low: 900.9,
+            close: 1218.1,
+            volume: 1000000.0,
+        }];
+
+        println!("{}", std_n_by_records(&records, 3))
+    }
+
+    #[test]
+    fn test_calc_gamma() {
+        println!("{}", calc_gamma(0.1, 49.0, 23.0))
+    }
+
+    #[test]
+    fn test_calc_deviation_range() {
+        let max_ira = 10.0;
+        let ira = 0.1;
+        let spread_list = vec![
+            0.1,
+            0.2,
+            0.15,
+            0.1
+        ];
+
+        println!("{}", calc_deviation_range(max_ira, &spread_list, ira));
+    }
+
+    #[test]
+    fn test_calc_rp() {
+        let mid_price = 1992.01;
+        let quantity = 49.0;
+        let ira = 0.1;
+        let gamma = 1.9289379267775165e-06;
+        let std = 23.0;
+
+        println!("{}", calc_rp(mid_price, quantity, ira, gamma, std));
+    }
+
+    #[test]
+    fn test_calc_dk() {
+        let deviation_range = 1.9900000000000002;
+        let ira = 0.1;
+        let gamma = 1.9289379267775165e-06;
+        let std = 23.0;
+
+        println!("{}", calc_dk(deviation_range, gamma, std, ira));
     }
-}
+
+    #[test]
+    fn test_calc_kappa() {
+        let deviation_range = 1.9900000000000002;
+        let ira = 0.1;
+        let gamma = 1.9289379267775165e-06;
+        let dk = 0.00000019191948219432835;
+
+        println!("{}", calc_kappa(gamma, dk, deviation_range, ira));
+    }
+
+    #[test]
+    fn test_calc_order_amount() {
+        let quantity = 400.0;
+        let quantity_max = 1000.0;
+        let bid_price = 30000.0;
+        let amount_decimal_places = 4;
+
+        let start = 0.1;
+        let end = 10.0;
+        let step = 0.1;
+        let mut ira = start;
+
+        while ira <= end {
+            println!("ira={}, order_amount={}", ira, calc_order_amount(end, ira, quantity, quantity_max, bid_price, amount_decimal_places));
+            ira += step;
+        }
+    }
+}

+ 7 - 1
src/exchange_libs.rs

@@ -2,7 +2,9 @@ use std::env;
 use reqwest;
 
 
-pub async fn binan_k(symbol: &String, interval: &String, limit: i32) -> String {
+
+/*币安-k线条*/
+pub async fn binan_k(symbol: &String, interval: &String, limit: &i32) -> String {
     let base_url = "https://api.binance.com/api/v3/klines?symbol=".to_string() + &symbol + "&interval=" + &interval + "&limit=" + &limit.to_string();
     let req = get(base_url.to_string());
     match req.await {
@@ -18,6 +20,10 @@ pub async fn binan_k(symbol: &String, interval: &String, limit: i32) -> String {
 }
 
 
+
+
+
+
 /*普通 Get 请求*/
 pub async fn get(url: String) -> Result<(String), reqwest::Error> {
     let mut conent = String::from("");