use napi::bindgen_prelude::*;
use napi::threadsafe_function::{ErrorStrategy, ThreadsafeFunction};
use napi_derive::napi;
use std::sync::Arc;
use tokio::sync::Mutex;
#[napi(object)]
pub struct Signal {
pub id: String,
pub strategy_id: String,
pub symbol: String,
pub direction: String, pub confidence: f64, pub entry_price: Option<f64>,
pub stop_loss: Option<f64>,
pub take_profit: Option<f64>,
pub reasoning: String,
pub timestamp_ns: i64,
}
#[napi(object)]
pub struct StrategyConfig {
pub name: String,
pub symbols: Vec<String>,
pub parameters: String, }
#[napi]
pub struct StrategyRunner {
strategies: Arc<Mutex<Vec<String>>>,
}
#[napi]
impl StrategyRunner {
#[napi(constructor)]
pub fn new() -> Self {
Self {
strategies: Arc::new(Mutex::new(Vec::new())),
}
}
#[napi]
pub async fn add_momentum_strategy(&self, config: StrategyConfig) -> Result<String> {
let strategy_id = format!("momentum-{}", generate_uuid());
let mut strategies = self.strategies.lock().await;
strategies.push(strategy_id.clone());
tracing::info!("Added momentum strategy: {} with config: {:?}", strategy_id, config.name);
Ok(strategy_id)
}
#[napi]
pub async fn add_mean_reversion_strategy(&self, _config: StrategyConfig) -> Result<String> {
let strategy_id = format!("mean-reversion-{}", generate_uuid());
let mut strategies = self.strategies.lock().await;
strategies.push(strategy_id.clone());
tracing::info!("Added mean reversion strategy: {}", strategy_id);
Ok(strategy_id)
}
#[napi]
pub async fn add_arbitrage_strategy(&self, _config: StrategyConfig) -> Result<String> {
let strategy_id = format!("arbitrage-{}", generate_uuid());
let mut strategies = self.strategies.lock().await;
strategies.push(strategy_id.clone());
tracing::info!("Added arbitrage strategy: {}", strategy_id);
Ok(strategy_id)
}
#[napi]
pub async fn generate_signals(&self) -> Result<Vec<Signal>> {
let strategies = self.strategies.lock().await;
let mut all_signals = Vec::new();
for strategy_id in strategies.iter() {
tracing::debug!("Generating signals for strategy: {}", strategy_id);
}
Ok(all_signals)
}
#[napi]
pub fn subscribe_signals(&self, callback: JsFunction) -> Result<SubscriptionHandle> {
let _tsfn: ThreadsafeFunction<Signal, ErrorStrategy::CalleeHandled> =
callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value]))?;
let strategies = self.strategies.clone();
let handle = tokio::spawn(async move {
loop {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
let _strategies = strategies.lock().await;
}
});
Ok(SubscriptionHandle {
handle: Arc::new(Mutex::new(Some(handle))),
})
}
#[napi]
pub async fn list_strategies(&self) -> Result<Vec<String>> {
let strategies = self.strategies.lock().await;
Ok(strategies.clone())
}
#[napi]
pub async fn remove_strategy(&self, strategy_id: String) -> Result<bool> {
let mut strategies = self.strategies.lock().await;
if let Some(pos) = strategies.iter().position(|id| id == &strategy_id) {
strategies.remove(pos);
tracing::info!("Removed strategy: {}", strategy_id);
Ok(true)
} else {
Ok(false)
}
}
}
#[napi]
pub struct SubscriptionHandle {
handle: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>,
}
#[napi]
impl SubscriptionHandle {
#[napi]
pub async fn unsubscribe(&self) -> Result<()> {
let mut guard = self.handle.lock().await;
if let Some(handle) = guard.take() {
handle.abort();
tracing::info!("Unsubscribed from signals");
}
Ok(())
}
}
fn generate_uuid() -> String {
use std::time::{SystemTime, UNIX_EPOCH};
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
format!("{:x}", nanos)
}