// ===========================
// File: src/live/meta.rs
// ===========================
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use redis::AsyncCommands;
use crate::redis::RedisCore;
use chrono::Utc;
/// Торговые метаданные для LIVE режима
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TradingMeta {
pub symbol: String,
pub price: f64,
pub bid: f64,
pub ask: f64,
pub bid_qty_depth: f64,
pub ask_qty_depth: f64,
pub chg_pct_24h: f64,
pub contract_multiplier: f64,
pub min_contracts: f64,
pub max_contracts: f64,
pub leverage_min: f64,
pub leverage_max: f64,
pub taker_fee_rate: f64,
pub maker_fee_rate: f64,
pub funding_rate: f64,
pub funding_rate_indicative: f64,
pub maintenance_rate: f64,
pub order_price_round: String,
pub order_price_deviate: String,
pub slippage_buy_1000_pct: f64,
pub slippage_sell_1000_pct: f64,
pub ts: i64,
}
/// Получение тикера из Redis → TradingMeta
pub async fn fetch_trading_meta(
redis: Arc<RedisCore>,
symbol: &str,
) -> Result<TradingMeta> {
// 🔧 ИСПРАВЛЕНО: было redis.conn(), должно быть get_conn()
let mut conn = redis.get_conn().await?;
let key = format!("hb:meta:{}", symbol);
let raw: Option<String> = conn.get(&key).await?;
let raw = match raw {
Some(v) => v,
None => return Err(anyhow::anyhow!("meta not found: {}", key)),
};
let tick_data: serde_json::Value = serde_json::from_str(&raw)?;
Ok(TradingMeta {
symbol: symbol.to_string(),
price: tick_data["price"].as_f64().unwrap_or(0.0),
bid: tick_data["bid"].as_f64().unwrap_or(0.0),
ask: tick_data["ask"].as_f64().unwrap_or(0.0),
bid_qty_depth: tick_data["bid_qty_depth"].as_f64().unwrap_or(0.0),
ask_qty_depth: tick_data["ask_qty_depth"].as_f64().unwrap_or(0.0),
chg_pct_24h: tick_data["chg_pct_24h"].as_f64().unwrap_or(0.0),
contract_multiplier: tick_data["contract_multiplier"].as_f64().unwrap_or(1.0),
min_contracts: tick_data["min_contracts"].as_f64().unwrap_or(1.0),
max_contracts: tick_data["max_contracts"].as_f64().unwrap_or(1_000_000.0),
leverage_min: tick_data["leverage_min"].as_f64().unwrap_or(1.0),
leverage_max: tick_data["leverage_max"].as_f64().unwrap_or(100.0),
taker_fee_rate: tick_data["taker_fee_rate"].as_f64().unwrap_or(0.0003),
maker_fee_rate: tick_data["maker_fee_rate"].as_f64().unwrap_or(0.0002),
funding_rate: tick_data["funding_rate"].as_f64().unwrap_or(0.0001),
funding_rate_indicative: tick_data["funding_rate_indicative"].as_f64().unwrap_or(0.0001),
maintenance_rate: tick_data["maintenance_rate"].as_f64().unwrap_or(0.01),
order_price_round: tick_data["order_price_round"].as_str().unwrap_or("0.000001").to_string(),
order_price_deviate: tick_data["order_price_deviate"].as_str().unwrap_or("0.2").to_string(),
slippage_buy_1000_pct: tick_data["slippage_buy_1000_pct"].as_f64().unwrap_or(0.0),
slippage_sell_1000_pct: tick_data["slippage_sell_1000_pct"].as_f64().unwrap_or(0.0),
ts: tick_data["timestamp"]
.as_i64()
.unwrap_or_else(|| Utc::now().timestamp()),
})
}
/// Значение по умолчанию для TradingMeta (fallback)
pub fn default_meta(symbol: &str) -> TradingMeta {
TradingMeta {
symbol: symbol.to_string(),
price: 0.0,
bid: 0.0,
ask: 0.0,
bid_qty_depth: 0.0,
ask_qty_depth: 0.0,
chg_pct_24h: 0.0,
contract_multiplier: 1.0,
min_contracts: 1.0,
max_contracts: 1_000_000.0,
leverage_min: 1.0,
leverage_max: 100.0,
taker_fee_rate: 0.0003,
maker_fee_rate: 0.0002,
funding_rate: 0.0001,
funding_rate_indicative: 0.0001,
maintenance_rate: 0.01,
order_price_round: "0.000001".to_string(),
order_price_deviate: "0.2".to_string(),
slippage_buy_1000_pct: 0.0,
slippage_sell_1000_pct: 0.0,
ts: Utc::now().timestamp(),
}
}