work on new engine
This commit is contained in:
parent
44476da13f
commit
a1e5a21847
126 changed files with 3425 additions and 6695 deletions
86
apps/stock/engine/src/api_new/backtest.rs
Normal file
86
apps/stock/engine/src/api_new/backtest.rs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
use napi_derive::napi;
|
||||
use napi::bindgen_prelude::*;
|
||||
use std::sync::Arc;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
#[napi]
|
||||
pub struct BacktestAPI {
|
||||
core: Arc<crate::TradingCore>,
|
||||
}
|
||||
|
||||
impl BacktestAPI {
|
||||
pub fn new(core: Arc<crate::TradingCore>) -> Self {
|
||||
Self { core }
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
impl BacktestAPI {
|
||||
#[napi]
|
||||
pub async fn configure(
|
||||
&self,
|
||||
start_date: String,
|
||||
end_date: String,
|
||||
symbols: Vec<String>,
|
||||
initial_capital: f64,
|
||||
commission: f64,
|
||||
slippage: f64,
|
||||
) -> Result<()> {
|
||||
// Parse dates
|
||||
let start = DateTime::parse_from_rfc3339(&start_date)
|
||||
.map_err(|e| Error::from_reason(format!("Invalid start date: {}", e)))?
|
||||
.with_timezone(&Utc);
|
||||
let end = DateTime::parse_from_rfc3339(&end_date)
|
||||
.map_err(|e| Error::from_reason(format!("Invalid end date: {}", e)))?
|
||||
.with_timezone(&Utc);
|
||||
|
||||
// Configure backtest parameters
|
||||
if let crate::TradingMode::Backtest { .. } = self.core.get_mode() {
|
||||
// Update backtest configuration
|
||||
todo!("Update backtest configuration")
|
||||
} else {
|
||||
return Err(Error::from_reason("Not in backtest mode"));
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub async fn load_data(&self, data_source: String) -> Result<()> {
|
||||
// Load historical data for backtest
|
||||
todo!("Load historical data")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub async fn run(&self) -> Result<JsObject> {
|
||||
// Run the backtest
|
||||
if let crate::TradingMode::Backtest { .. } = self.core.get_mode() {
|
||||
// Execute backtest
|
||||
todo!("Execute backtest")
|
||||
} else {
|
||||
return Err(Error::from_reason("Not in backtest mode"));
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_progress(&self) -> Result<f64> {
|
||||
// Get backtest progress (0.0 to 1.0)
|
||||
todo!("Get backtest progress")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn pause(&self) -> Result<()> {
|
||||
// Pause backtest execution
|
||||
todo!("Pause backtest")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn resume(&self) -> Result<()> {
|
||||
// Resume backtest execution
|
||||
todo!("Resume backtest")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_results(&self) -> Result<JsObject> {
|
||||
// Get backtest results
|
||||
todo!("Get backtest results")
|
||||
}
|
||||
}
|
||||
51
apps/stock/engine/src/api_new/market_data.rs
Normal file
51
apps/stock/engine/src/api_new/market_data.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
use napi_derive::napi;
|
||||
use napi::bindgen_prelude::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[napi]
|
||||
pub struct MarketDataAPI {
|
||||
core: Arc<crate::TradingCore>,
|
||||
}
|
||||
|
||||
impl MarketDataAPI {
|
||||
pub fn new(core: Arc<crate::TradingCore>) -> Self {
|
||||
Self { core }
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
impl MarketDataAPI {
|
||||
#[napi]
|
||||
pub async fn subscribe(&self, symbols: Vec<String>) -> Result<()> {
|
||||
// Subscribe to market data for symbols
|
||||
self.core.subscribe_market_data(symbols)
|
||||
.await
|
||||
.map_err(|e| Error::from_reason(e))
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub async fn unsubscribe(&self, symbols: Vec<String>) -> Result<()> {
|
||||
// Unsubscribe from market data
|
||||
self.core.unsubscribe_market_data(symbols)
|
||||
.await
|
||||
.map_err(|e| Error::from_reason(e))
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_latest_quote(&self, symbol: String) -> Result<JsObject> {
|
||||
// Get latest quote for symbol
|
||||
let quote = self.core.orderbook_manager
|
||||
.get_best_bid_ask(&symbol)
|
||||
.ok_or_else(|| Error::from_reason("No quote available"))?;
|
||||
|
||||
// Convert to JS object
|
||||
// Note: In real implementation, would properly convert Quote to JsObject
|
||||
todo!("Convert quote to JsObject")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_latest_bar(&self, symbol: String) -> Result<JsObject> {
|
||||
// Get latest bar for symbol
|
||||
todo!("Get latest bar implementation")
|
||||
}
|
||||
}
|
||||
76
apps/stock/engine/src/api_new/mod.rs
Normal file
76
apps/stock/engine/src/api_new/mod.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
use napi_derive::napi;
|
||||
|
||||
pub mod market_data;
|
||||
pub mod orders;
|
||||
pub mod positions;
|
||||
pub mod backtest;
|
||||
pub mod strategies;
|
||||
pub mod system;
|
||||
|
||||
// Main API entry point
|
||||
#[napi]
|
||||
pub struct TradingAPI {
|
||||
inner: std::sync::Arc<crate::TradingCore>,
|
||||
}
|
||||
|
||||
#[napi]
|
||||
impl TradingAPI {
|
||||
#[napi(constructor)]
|
||||
pub fn new(mode: String) -> napi::Result<Self> {
|
||||
let trading_mode = parse_mode(&mode)?;
|
||||
let core = crate::TradingCore::new(trading_mode)
|
||||
.map_err(|e| napi::Error::from_reason(e))?;
|
||||
|
||||
Ok(Self {
|
||||
inner: std::sync::Arc::new(core),
|
||||
})
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn market_data(&self) -> market_data::MarketDataAPI {
|
||||
market_data::MarketDataAPI::new(self.inner.clone())
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn orders(&self) -> orders::OrdersAPI {
|
||||
orders::OrdersAPI::new(self.inner.clone())
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn positions(&self) -> positions::PositionsAPI {
|
||||
positions::PositionsAPI::new(self.inner.clone())
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn strategies(&self) -> strategies::StrategiesAPI {
|
||||
strategies::StrategiesAPI::new(self.inner.clone())
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn system(&self) -> system::SystemAPI {
|
||||
system::SystemAPI::new(self.inner.clone())
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn backtest(&self) -> backtest::BacktestAPI {
|
||||
backtest::BacktestAPI::new(self.inner.clone())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_mode(mode: &str) -> napi::Result<crate::TradingMode> {
|
||||
match mode {
|
||||
"backtest" => Ok(crate::TradingMode::Backtest {
|
||||
start_time: chrono::Utc::now(),
|
||||
end_time: chrono::Utc::now(),
|
||||
speed_multiplier: 1.0,
|
||||
}),
|
||||
"paper" => Ok(crate::TradingMode::Paper {
|
||||
starting_capital: 100_000.0,
|
||||
}),
|
||||
"live" => Ok(crate::TradingMode::Live {
|
||||
broker: "default".to_string(),
|
||||
account_id: "default".to_string(),
|
||||
}),
|
||||
_ => Err(napi::Error::from_reason(format!("Unknown mode: {}", mode))),
|
||||
}
|
||||
}
|
||||
87
apps/stock/engine/src/api_new/orders.rs
Normal file
87
apps/stock/engine/src/api_new/orders.rs
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
use napi_derive::napi;
|
||||
use napi::bindgen_prelude::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[napi]
|
||||
pub struct OrdersAPI {
|
||||
core: Arc<crate::TradingCore>,
|
||||
}
|
||||
|
||||
impl OrdersAPI {
|
||||
pub fn new(core: Arc<crate::TradingCore>) -> Self {
|
||||
Self { core }
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
impl OrdersAPI {
|
||||
#[napi]
|
||||
pub async fn submit_order(
|
||||
&self,
|
||||
symbol: String,
|
||||
side: String,
|
||||
quantity: f64,
|
||||
order_type: String,
|
||||
limit_price: Option<f64>,
|
||||
stop_price: Option<f64>,
|
||||
) -> Result<String> {
|
||||
let side = match side.as_str() {
|
||||
"buy" => crate::Side::Buy,
|
||||
"sell" => crate::Side::Sell,
|
||||
_ => return Err(Error::from_reason("Invalid side")),
|
||||
};
|
||||
|
||||
let order_type = match order_type.as_str() {
|
||||
"market" => crate::OrderType::Market,
|
||||
"limit" => {
|
||||
let price = limit_price.ok_or_else(|| Error::from_reason("Limit price required"))?;
|
||||
crate::OrderType::Limit { price }
|
||||
}
|
||||
"stop" => {
|
||||
let price = stop_price.ok_or_else(|| Error::from_reason("Stop price required"))?;
|
||||
crate::OrderType::Stop { stop_price: price }
|
||||
}
|
||||
"stop_limit" => {
|
||||
let stop = stop_price.ok_or_else(|| Error::from_reason("Stop price required"))?;
|
||||
let limit = limit_price.ok_or_else(|| Error::from_reason("Limit price required"))?;
|
||||
crate::OrderType::StopLimit { stop_price: stop, limit_price: limit }
|
||||
}
|
||||
_ => return Err(Error::from_reason("Invalid order type")),
|
||||
};
|
||||
|
||||
let order = crate::Order {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
symbol,
|
||||
side,
|
||||
quantity,
|
||||
order_type,
|
||||
time_in_force: crate::TimeInForce::Day,
|
||||
};
|
||||
|
||||
let result = self.core.execution_handler
|
||||
.write()
|
||||
.execute_order(order)
|
||||
.await
|
||||
.map_err(|e| Error::from_reason(e))?;
|
||||
|
||||
Ok(result.order_id)
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub async fn cancel_order(&self, order_id: String) -> Result<()> {
|
||||
// Cancel order implementation
|
||||
todo!("Cancel order implementation")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_pending_orders(&self) -> Result<Vec<JsObject>> {
|
||||
// Get pending orders
|
||||
todo!("Get pending orders implementation")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_order_history(&self) -> Result<Vec<JsObject>> {
|
||||
// Get order history
|
||||
todo!("Get order history implementation")
|
||||
}
|
||||
}
|
||||
67
apps/stock/engine/src/api_new/positions.rs
Normal file
67
apps/stock/engine/src/api_new/positions.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
use napi_derive::napi;
|
||||
use napi::bindgen_prelude::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[napi]
|
||||
pub struct PositionsAPI {
|
||||
core: Arc<crate::TradingCore>,
|
||||
}
|
||||
|
||||
impl PositionsAPI {
|
||||
pub fn new(core: Arc<crate::TradingCore>) -> Self {
|
||||
Self { core }
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
impl PositionsAPI {
|
||||
#[napi]
|
||||
pub fn get_position(&self, symbol: String) -> Result<JsObject> {
|
||||
let position = self.core.position_tracker
|
||||
.get_position(&symbol)
|
||||
.ok_or_else(|| Error::from_reason("No position found"))?;
|
||||
|
||||
// Convert position to JsObject
|
||||
todo!("Convert position to JsObject")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_all_positions(&self) -> Result<Vec<JsObject>> {
|
||||
let positions = self.core.position_tracker.get_all_positions();
|
||||
|
||||
// Convert positions to JsObjects
|
||||
todo!("Convert positions to JsObjects")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_closed_trades(&self) -> Result<Vec<JsObject>> {
|
||||
let trades = self.core.position_tracker.get_closed_trades();
|
||||
|
||||
// Convert trades to JsObjects
|
||||
todo!("Convert trades to JsObjects")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_pnl(&self, symbol: Option<String>) -> Result<f64> {
|
||||
if let Some(sym) = symbol {
|
||||
// Get P&L for specific symbol
|
||||
let position = self.core.position_tracker
|
||||
.get_position(&sym)
|
||||
.ok_or_else(|| Error::from_reason("No position found"))?;
|
||||
Ok(position.realized_pnl + position.unrealized_pnl)
|
||||
} else {
|
||||
// Get total P&L
|
||||
let positions = self.core.position_tracker.get_all_positions();
|
||||
let total_pnl = positions.into_iter()
|
||||
.map(|p| p.realized_pnl + p.unrealized_pnl)
|
||||
.sum();
|
||||
Ok(total_pnl)
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_portfolio_value(&self) -> Result<f64> {
|
||||
// Calculate total portfolio value
|
||||
todo!("Calculate portfolio value")
|
||||
}
|
||||
}
|
||||
76
apps/stock/engine/src/api_new/strategies.rs
Normal file
76
apps/stock/engine/src/api_new/strategies.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
use napi_derive::napi;
|
||||
use napi::bindgen_prelude::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[napi]
|
||||
pub struct StrategiesAPI {
|
||||
core: Arc<crate::TradingCore>,
|
||||
}
|
||||
|
||||
impl StrategiesAPI {
|
||||
pub fn new(core: Arc<crate::TradingCore>) -> Self {
|
||||
Self { core }
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
impl StrategiesAPI {
|
||||
#[napi]
|
||||
pub async fn add_strategy(
|
||||
&self,
|
||||
name: String,
|
||||
strategy_type: String,
|
||||
parameters: String,
|
||||
) -> Result<String> {
|
||||
// Parse parameters from JSON string
|
||||
let params: serde_json::Value = serde_json::from_str(¶meters)
|
||||
.map_err(|e| Error::from_reason(format!("Invalid parameters: {}", e)))?;
|
||||
|
||||
// Create strategy based on type
|
||||
let strategy = match strategy_type.as_str() {
|
||||
"sma_crossover" => {
|
||||
// Create SMA crossover strategy
|
||||
todo!("Create SMA strategy")
|
||||
}
|
||||
"momentum" => {
|
||||
// Create momentum strategy
|
||||
todo!("Create momentum strategy")
|
||||
}
|
||||
_ => return Err(Error::from_reason("Unknown strategy type")),
|
||||
};
|
||||
|
||||
// Add strategy to core
|
||||
todo!("Add strategy to core")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub async fn remove_strategy(&self, strategy_id: String) -> Result<()> {
|
||||
// Remove strategy
|
||||
todo!("Remove strategy implementation")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_strategies(&self) -> Result<Vec<JsObject>> {
|
||||
// Get all active strategies
|
||||
todo!("Get strategies implementation")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub async fn update_strategy_parameters(
|
||||
&self,
|
||||
strategy_id: String,
|
||||
parameters: String,
|
||||
) -> Result<()> {
|
||||
// Parse and update parameters
|
||||
let params: serde_json::Value = serde_json::from_str(¶meters)
|
||||
.map_err(|e| Error::from_reason(format!("Invalid parameters: {}", e)))?;
|
||||
|
||||
todo!("Update strategy parameters")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_strategy_performance(&self, strategy_id: String) -> Result<JsObject> {
|
||||
// Get performance metrics for strategy
|
||||
todo!("Get strategy performance")
|
||||
}
|
||||
}
|
||||
77
apps/stock/engine/src/api_new/system.rs
Normal file
77
apps/stock/engine/src/api_new/system.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
use napi_derive::napi;
|
||||
use napi::bindgen_prelude::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[napi]
|
||||
pub struct SystemAPI {
|
||||
core: Arc<crate::TradingCore>,
|
||||
}
|
||||
|
||||
impl SystemAPI {
|
||||
pub fn new(core: Arc<crate::TradingCore>) -> Self {
|
||||
Self { core }
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
impl SystemAPI {
|
||||
#[napi]
|
||||
pub async fn start(&self) -> Result<()> {
|
||||
// Start the trading system
|
||||
match self.core.get_mode() {
|
||||
crate::TradingMode::Backtest { .. } => {
|
||||
// Start backtest processing
|
||||
todo!("Start backtest")
|
||||
}
|
||||
crate::TradingMode::Paper { .. } => {
|
||||
// Start paper trading
|
||||
todo!("Start paper trading")
|
||||
}
|
||||
crate::TradingMode::Live { .. } => {
|
||||
// Start live trading
|
||||
todo!("Start live trading")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub async fn stop(&self) -> Result<()> {
|
||||
// Stop the trading system
|
||||
todo!("Stop trading system")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_mode(&self) -> String {
|
||||
match self.core.get_mode() {
|
||||
crate::TradingMode::Backtest { .. } => "backtest".to_string(),
|
||||
crate::TradingMode::Paper { .. } => "paper".to_string(),
|
||||
crate::TradingMode::Live { .. } => "live".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_current_time(&self) -> String {
|
||||
self.core.get_time().to_rfc3339()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn set_risk_limits(&self, limits: String) -> Result<()> {
|
||||
// Parse and set risk limits
|
||||
let limits: serde_json::Value = serde_json::from_str(&limits)
|
||||
.map_err(|e| Error::from_reason(format!("Invalid limits: {}", e)))?;
|
||||
|
||||
todo!("Set risk limits")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_risk_metrics(&self) -> Result<JsObject> {
|
||||
// Get current risk metrics
|
||||
todo!("Get risk metrics")
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn get_analytics(&self) -> Result<JsObject> {
|
||||
// Get trading analytics
|
||||
todo!("Get analytics")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue