|
|
@@ -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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|