100 lines
No EOL
2.8 KiB
Rust
100 lines
No EOL
2.8 KiB
Rust
use chrono::{DateTime, Utc};
|
|
use serde::{Serialize, Deserialize};
|
|
use crate::MarketData;
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub enum SignalType {
|
|
Buy,
|
|
Sell,
|
|
Close,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct Signal {
|
|
pub symbol: String,
|
|
pub signal_type: SignalType,
|
|
pub strength: f64, // -1.0 to 1.0
|
|
pub quantity: Option<f64>,
|
|
pub reason: Option<String>,
|
|
pub metadata: Option<serde_json::Value>,
|
|
}
|
|
|
|
// This trait will be implemented by Rust strategies
|
|
// TypeScript strategies will communicate through FFI
|
|
pub trait Strategy: Send + Sync {
|
|
fn on_market_data(&mut self, data: &MarketData) -> Vec<Signal>;
|
|
fn on_fill(&mut self, symbol: &str, quantity: f64, price: f64, side: &str);
|
|
fn get_name(&self) -> &str;
|
|
fn get_parameters(&self) -> serde_json::Value;
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct StrategyCall {
|
|
pub method: String,
|
|
pub data: serde_json::Value,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct StrategyResponse {
|
|
pub signals: Vec<Signal>,
|
|
}
|
|
|
|
// Bridge for TypeScript strategies
|
|
|
|
// This will be used to wrap TypeScript strategies
|
|
pub struct TypeScriptStrategy {
|
|
pub name: String,
|
|
pub id: String,
|
|
pub parameters: serde_json::Value,
|
|
// Callback function will be injected from TypeScript
|
|
pub callback: Option<Box<dyn Fn(StrategyCall) -> StrategyResponse + Send + Sync>>,
|
|
}
|
|
|
|
impl TypeScriptStrategy {
|
|
pub fn new(name: String, id: String, parameters: serde_json::Value) -> Self {
|
|
Self {
|
|
name,
|
|
id,
|
|
parameters,
|
|
callback: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Strategy for TypeScriptStrategy {
|
|
fn on_market_data(&mut self, data: &MarketData) -> Vec<Signal> {
|
|
if let Some(callback) = &self.callback {
|
|
let call = StrategyCall {
|
|
method: "on_market_data".to_string(),
|
|
data: serde_json::to_value(data).unwrap_or_default(),
|
|
};
|
|
let response = callback(call);
|
|
response.signals
|
|
} else {
|
|
Vec::new()
|
|
}
|
|
}
|
|
|
|
fn on_fill(&mut self, symbol: &str, quantity: f64, price: f64, side: &str) {
|
|
if let Some(callback) = &self.callback {
|
|
let call = StrategyCall {
|
|
method: "on_fill".to_string(),
|
|
data: serde_json::json!({
|
|
"symbol": symbol,
|
|
"quantity": quantity,
|
|
"price": price,
|
|
"side": side
|
|
}),
|
|
};
|
|
callback(call);
|
|
}
|
|
}
|
|
|
|
fn get_name(&self) -> &str {
|
|
&self.name
|
|
}
|
|
|
|
fn get_parameters(&self) -> serde_json::Value {
|
|
self.parameters.clone()
|
|
}
|
|
} |