moving engine to rust
This commit is contained in:
parent
d14380d740
commit
16ac28a565
16 changed files with 1598 additions and 3 deletions
112
apps/stock/core/src/backtest/mod.rs
Normal file
112
apps/stock/core/src/backtest/mod.rs
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
use crate::{MarketUpdate, Order, Fill, TradingMode, MarketDataSource, ExecutionHandler, TimeProvider};
|
||||
use crate::positions::PositionTracker;
|
||||
use crate::risk::RiskEngine;
|
||||
use crate::orderbook::OrderBookManager;
|
||||
use chrono::{DateTime, Utc};
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::sync::Arc;
|
||||
use parking_lot::RwLock;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
pub mod engine;
|
||||
pub mod event;
|
||||
pub mod strategy;
|
||||
pub mod results;
|
||||
|
||||
pub use engine::BacktestEngine;
|
||||
pub use event::{BacktestEvent, EventType};
|
||||
pub use strategy::{Strategy, Signal, SignalType};
|
||||
pub use results::{BacktestResult, BacktestMetrics};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BacktestConfig {
|
||||
pub name: String,
|
||||
pub symbols: Vec<String>,
|
||||
pub start_time: DateTime<Utc>,
|
||||
pub end_time: DateTime<Utc>,
|
||||
pub initial_capital: f64,
|
||||
pub commission: f64,
|
||||
pub slippage: f64,
|
||||
pub data_frequency: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BacktestState {
|
||||
pub current_time: DateTime<Utc>,
|
||||
pub portfolio_value: f64,
|
||||
pub cash: f64,
|
||||
pub equity_curve: Vec<(DateTime<Utc>, f64)>,
|
||||
pub pending_orders: BTreeMap<String, Order>,
|
||||
pub completed_trades: Vec<Fill>,
|
||||
}
|
||||
|
||||
impl BacktestState {
|
||||
pub fn new(initial_capital: f64, start_time: DateTime<Utc>) -> Self {
|
||||
Self {
|
||||
current_time: start_time,
|
||||
portfolio_value: initial_capital,
|
||||
cash: initial_capital,
|
||||
equity_curve: vec![(start_time, initial_capital)],
|
||||
pending_orders: BTreeMap::new(),
|
||||
completed_trades: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_portfolio_value(&mut self, value: f64) {
|
||||
self.portfolio_value = value;
|
||||
self.equity_curve.push((self.current_time, value));
|
||||
}
|
||||
|
||||
pub fn add_pending_order(&mut self, order: Order) {
|
||||
self.pending_orders.insert(order.id.clone(), order);
|
||||
}
|
||||
|
||||
pub fn remove_pending_order(&mut self, order_id: &str) -> Option<Order> {
|
||||
self.pending_orders.remove(order_id)
|
||||
}
|
||||
|
||||
pub fn record_fill(&mut self, fill: Fill) {
|
||||
self.completed_trades.push(fill);
|
||||
}
|
||||
}
|
||||
|
||||
// Event queue for deterministic replay
|
||||
#[derive(Debug)]
|
||||
pub struct EventQueue {
|
||||
events: VecDeque<BacktestEvent>,
|
||||
}
|
||||
|
||||
impl EventQueue {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
events: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, event: BacktestEvent) {
|
||||
// Insert in time order
|
||||
let pos = self.events.iter().position(|e| e.timestamp > event.timestamp)
|
||||
.unwrap_or(self.events.len());
|
||||
self.events.insert(pos, event);
|
||||
}
|
||||
|
||||
pub fn pop_until(&mut self, timestamp: DateTime<Utc>) -> Vec<BacktestEvent> {
|
||||
let mut events = Vec::new();
|
||||
while let Some(event) = self.events.front() {
|
||||
if event.timestamp <= timestamp {
|
||||
events.push(self.events.pop_front().unwrap());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
events
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.events.is_empty()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.events.len()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue