|
|
@@ -1,14 +1,15 @@
|
|
|
use std::cmp::{max, min};
|
|
|
+use std::collections::HashMap;
|
|
|
use std::str::FromStr;
|
|
|
use actix_web::{HttpResponse};
|
|
|
use chrono::Utc;
|
|
|
-use rust_decimal::{Decimal};
|
|
|
+use rust_decimal::{Decimal, MathematicalOps};
|
|
|
use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
|
|
|
use rust_decimal_macros::dec;
|
|
|
use serde_json::{json, Value};
|
|
|
-use crate::db_connector::{get_simple_depths_json, get_trades_json};
|
|
|
+use crate::db_connector::{get_force_orders_json, get_simple_depths_json, get_trades_json};
|
|
|
use crate::params_utils::{get_str, parse_str_to_decimal};
|
|
|
-use crate::server::{Response, SimpleDepth, Trade};
|
|
|
+use crate::server::{ForceOrder, Response, SimpleDepth, Trade};
|
|
|
|
|
|
pub fn symbol_fix(symbol: &str) -> String {
|
|
|
let mut fixed = symbol.to_uppercase();
|
|
|
@@ -419,6 +420,172 @@ pub fn generate_msv_by_trades(mut trades: Vec<Trade>, mills_back: Decimal, simpl
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+pub async fn generate_fot(query_value: Value) -> HttpResponse {
|
|
|
+ // 参数处理
|
|
|
+ let exchange = match get_str(query_value.clone(), "exchange") {
|
|
|
+ Ok(str) => {
|
|
|
+ str
|
|
|
+ }
|
|
|
+ Err(response) => {
|
|
|
+ return response
|
|
|
+ }
|
|
|
+ };
|
|
|
+ let symbol = match get_str(query_value.clone(), "symbol") {
|
|
|
+ Ok(symbol) => {
|
|
|
+ symbol_fix(symbol.as_str())
|
|
|
+ }
|
|
|
+ Err(response) => {
|
|
|
+ return response
|
|
|
+ }
|
|
|
+ };
|
|
|
+ let minute_time_range = match parse_str_to_decimal(query_value.clone(), "minute_time_range") {
|
|
|
+ Ok(t) => {
|
|
|
+ t.to_i64().unwrap()
|
|
|
+ }
|
|
|
+ Err(response) => {
|
|
|
+ return response
|
|
|
+ }
|
|
|
+ };
|
|
|
+ let value_ln = match parse_str_to_decimal(query_value.clone(), "value_ln") {
|
|
|
+ Ok(t) => {
|
|
|
+ t
|
|
|
+ }
|
|
|
+ Err(response) => {
|
|
|
+ return response
|
|
|
+ }
|
|
|
+ };
|
|
|
+ // 链接数据服务器查询数据
|
|
|
+ let end_time = Utc::now().timestamp_millis();
|
|
|
+ let start_time = end_time - minute_time_range * 60 * 1000;
|
|
|
+ let trades_response = get_trades_json(
|
|
|
+ exchange.as_str(),
|
|
|
+ symbol.as_str(),
|
|
|
+ start_time,
|
|
|
+ end_time,
|
|
|
+ ).await;
|
|
|
+ let force_orders_response = get_force_orders_json(
|
|
|
+ exchange.as_str(),
|
|
|
+ symbol.as_str(),
|
|
|
+ start_time,
|
|
|
+ end_time,
|
|
|
+ ).await;
|
|
|
+
|
|
|
+ // 对数据库返回的数据进行容错处理
|
|
|
+ if trades_response.code == 200 && force_orders_response.code == 200 {
|
|
|
+ // trades数据处理
|
|
|
+ let mut trades = parse_json_to_trades(trades_response.data);
|
|
|
+ // 按时间顺序排列trades数据
|
|
|
+ trades.sort_by(|a, b| a.time.cmp(&b.time));
|
|
|
+ // 处理trade,一秒只需要一个数据
|
|
|
+ let mut processed_trades: HashMap<Decimal, Decimal> = HashMap::new();
|
|
|
+ for trade in &trades {
|
|
|
+ let mut insert_time_second = trade.time / Decimal::ONE_THOUSAND;
|
|
|
+ insert_time_second.rescale(0);
|
|
|
+
|
|
|
+ // 如若是空值,直接插入
|
|
|
+ if processed_trades.get(&insert_time_second).is_none() {
|
|
|
+ processed_trades.insert(insert_time_second, trade.price);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // force_orders处理
|
|
|
+ let force_orders = parse_json_to_force_orders(force_orders_response.data);
|
|
|
+
|
|
|
+ let indicator = generate_fot_by_trades(processed_trades, force_orders, value_ln);
|
|
|
+
|
|
|
+ // 返回数据
|
|
|
+ let response = Response {
|
|
|
+ query: query_value.clone(),
|
|
|
+ msg: Some("指标生成完毕".to_string()),
|
|
|
+ code: 200,
|
|
|
+ data: indicator,
|
|
|
+ };
|
|
|
+
|
|
|
+ let json_string = serde_json::to_string(&response).unwrap();
|
|
|
+ HttpResponse::Ok().content_type("application/json").body(json_string)
|
|
|
+ } else {
|
|
|
+ let json_string = serde_json::to_string(&trades_response).unwrap();
|
|
|
+ HttpResponse::Ok().content_type("application/json").body(json_string)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub fn generate_fot_by_trades(processed_trades: HashMap<Decimal, Decimal>, force_orders: Vec<ForceOrder>, value_limit_ln: Decimal) -> Value {
|
|
|
+ let mut profits_rst: Vec<Vec<Decimal>> = vec![];
|
|
|
+ // 外层遍历信号源
|
|
|
+ for force_order in force_orders {
|
|
|
+ let force_value = if force_order.value > Decimal::ONE {
|
|
|
+ force_order.value.ln()
|
|
|
+ } else if force_order.value < Decimal::NEGATIVE_ONE {
|
|
|
+ -force_order.value.abs().ln()
|
|
|
+ } else {
|
|
|
+ Decimal::ZERO
|
|
|
+ };
|
|
|
+
|
|
|
+ // 小于设定的阈值,就不交易
|
|
|
+ if force_value.abs() < value_limit_ln {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ let mut trade_second = force_order.time / Decimal::ONE_THOUSAND;
|
|
|
+ trade_second.rescale(0);
|
|
|
+
|
|
|
+ let first_trade_price = match processed_trades.get(&trade_second) {
|
|
|
+ None => {
|
|
|
+ force_order.price
|
|
|
+ }
|
|
|
+ Some(price) => {
|
|
|
+ price.clone()
|
|
|
+ }
|
|
|
+ };
|
|
|
+ let mut prev_calc_price = first_trade_price;
|
|
|
+
|
|
|
+ // 开始统计每一秒的收益率
|
|
|
+ let mut profit_list: Vec<Decimal> = vec![];
|
|
|
+ for next_time_int in 1..3601 {
|
|
|
+ let next_time = Decimal::from(next_time_int);
|
|
|
+
|
|
|
+ let calc_price = match processed_trades.get(&(trade_second + next_time)) {
|
|
|
+ None => {
|
|
|
+ prev_calc_price
|
|
|
+ }
|
|
|
+ Some(trade_price) => {
|
|
|
+ trade_price.clone()
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 求收益率
|
|
|
+ let mut profit = (calc_price / first_trade_price) - Decimal::ONE;
|
|
|
+ profit.rescale(4);
|
|
|
+ // 负数另考虑
|
|
|
+ if force_value < Decimal::ZERO {
|
|
|
+ profit = -profit;
|
|
|
+ }
|
|
|
+
|
|
|
+ profit_list.push(profit);
|
|
|
+
|
|
|
+ prev_calc_price = calc_price;
|
|
|
+ }
|
|
|
+
|
|
|
+ profits_rst.push(profit_list)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ let mut profit_total_list: Vec<Decimal> = vec![];
|
|
|
+ for index in 0usize..3600usize {
|
|
|
+ let mut total_profit = Decimal::ZERO;
|
|
|
+
|
|
|
+ for profit_list in &profits_rst {
|
|
|
+ total_profit += profit_list[index]
|
|
|
+ }
|
|
|
+
|
|
|
+ profit_total_list.push(total_profit)
|
|
|
+ }
|
|
|
+
|
|
|
+ json!({
|
|
|
+ "profits": profits_rst,
|
|
|
+ "profit_total_list": profit_total_list,
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
// 将json转换为trades
|
|
|
pub fn parse_json_to_trades(trades_json: Value) -> Vec<Trade> {
|
|
|
let mut rst = vec![];
|
|
|
@@ -436,6 +603,24 @@ pub fn parse_json_to_trades(trades_json: Value) -> Vec<Trade> {
|
|
|
rst
|
|
|
}
|
|
|
|
|
|
+pub fn parse_json_to_force_orders(force_orders_json: Value) -> Vec<ForceOrder> {
|
|
|
+ let mut rst = vec![];
|
|
|
+
|
|
|
+ for force_order_json in force_orders_json.as_array().unwrap() {
|
|
|
+ let force_order = ForceOrder {
|
|
|
+ time: Decimal::from_str(force_order_json["time"].as_str().unwrap()).unwrap(),
|
|
|
+ symbol: "".to_string(),
|
|
|
+ price: Decimal::from_str(force_order_json["price"].as_str().unwrap()).unwrap(),
|
|
|
+ amount: Decimal::from_str(force_order_json["amount"].as_str().unwrap()).unwrap(),
|
|
|
+ value: Decimal::from_str(force_order_json["value"].as_str().unwrap()).unwrap(),
|
|
|
+ };
|
|
|
+
|
|
|
+ rst.insert(0, force_order)
|
|
|
+ }
|
|
|
+
|
|
|
+ rst
|
|
|
+}
|
|
|
+
|
|
|
// // 将json转换为简易深度数据
|
|
|
// pub fn parse_json_to_simple_depths(depths_json: Value) -> Vec<SimpleDepth> {
|
|
|
// let mut rst = vec![];
|