work on integrating new system
This commit is contained in:
parent
083dca500c
commit
063f4c8e27
8 changed files with 221 additions and 66 deletions
Binary file not shown.
|
|
@ -63,8 +63,9 @@ impl BacktestEngine {
|
|||
) -> Result<()> {
|
||||
// For now, let's use a simple SMA crossover strategy directly in Rust
|
||||
// This bypasses the TypeScript callback complexity
|
||||
let fast_period = 10;
|
||||
let slow_period = 30;
|
||||
// Use shorter periods for testing with low volatility mock data
|
||||
let fast_period = 5;
|
||||
let slow_period = 15;
|
||||
|
||||
if let Some(engine) = self.inner.lock().as_mut() {
|
||||
engine.add_strategy(Box::new(SimpleSMAStrategy::new(
|
||||
|
|
@ -104,19 +105,29 @@ impl BacktestEngine {
|
|||
|
||||
#[napi]
|
||||
pub fn load_market_data(&self, data: Vec<napi::JsObject>) -> Result<()> {
|
||||
eprintln!("load_market_data called with {} items", data.len());
|
||||
|
||||
// Convert JS objects to MarketData
|
||||
let market_data: Vec<MarketUpdate> = data.into_iter()
|
||||
.filter_map(|obj| parse_market_data(obj).ok())
|
||||
.collect();
|
||||
|
||||
eprintln!("Parsed {} valid market data items", market_data.len());
|
||||
|
||||
// Load data into the historical data source
|
||||
if let Some(engine) = self.inner.lock().as_ref() {
|
||||
// Access the market data source through the engine
|
||||
let mut data_source = engine.market_data_source.write();
|
||||
if let Some(historical_source) = data_source.as_any_mut()
|
||||
.downcast_mut::<crate::core::market_data_sources::HistoricalDataSource>() {
|
||||
eprintln!("Loading data into HistoricalDataSource");
|
||||
historical_source.load_data(market_data);
|
||||
eprintln!("Data loaded successfully");
|
||||
} else {
|
||||
eprintln!("ERROR: Could not downcast to HistoricalDataSource");
|
||||
}
|
||||
} else {
|
||||
eprintln!("ERROR: Engine not found");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -186,9 +197,21 @@ fn parse_market_data(obj: napi::JsObject) -> Result<crate::MarketUpdate> {
|
|||
vwap: obj.get_named_property("vwap").ok(),
|
||||
})
|
||||
} else {
|
||||
eprintln!("Unsupported market data type: {}", data_type);
|
||||
return Err(Error::from_reason("Unsupported market data type"));
|
||||
};
|
||||
|
||||
// First few items
|
||||
static mut COUNT: usize = 0;
|
||||
unsafe {
|
||||
if COUNT < 3 {
|
||||
eprintln!("Parsed market data: symbol={}, timestamp={}, close={}",
|
||||
symbol, timestamp,
|
||||
if let crate::MarketDataType::Bar(ref bar) = data { bar.close } else { 0.0 });
|
||||
COUNT += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(crate::MarketUpdate {
|
||||
symbol,
|
||||
timestamp: DateTime::<Utc>::from_timestamp(timestamp / 1000, 0)
|
||||
|
|
@ -233,6 +256,11 @@ impl Strategy for SimpleSMAStrategy {
|
|||
let history = self.price_history.entry(symbol.clone()).or_insert_with(Vec::new);
|
||||
history.push(price);
|
||||
|
||||
// Debug: Log first few prices
|
||||
if history.len() <= 3 {
|
||||
eprintln!("Price history for {}: {:?}", symbol, history);
|
||||
}
|
||||
|
||||
// Keep only necessary history
|
||||
if history.len() > self.slow_period {
|
||||
history.remove(0);
|
||||
|
|
@ -244,6 +272,11 @@ impl Strategy for SimpleSMAStrategy {
|
|||
let fast_sma = history[history.len() - self.fast_period..].iter().sum::<f64>() / self.fast_period as f64;
|
||||
let slow_sma = history.iter().sum::<f64>() / history.len() as f64;
|
||||
|
||||
// Debug: Log SMAs periodically
|
||||
if history.len() % 10 == 0 {
|
||||
eprintln!("SMAs for {}: fast={:.2}, slow={:.2}, price={:.2}", symbol, fast_sma, slow_sma, price);
|
||||
}
|
||||
|
||||
// Previous SMAs (if we have enough history)
|
||||
if history.len() > self.slow_period {
|
||||
let prev_history = &history[..history.len() - 1];
|
||||
|
|
@ -280,6 +313,11 @@ impl Strategy for SimpleSMAStrategy {
|
|||
eprintln!("Generated SELL signal for {} at price {}", symbol, price);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Debug: Log when we don't have enough data
|
||||
if history.len() == 1 || history.len() == 10 || history.len() == 20 {
|
||||
eprintln!("Not enough data for {}: {} bars (need {})", symbol, history.len(), self.slow_period);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -85,56 +85,74 @@ impl BacktestEngine {
|
|||
// Load market data
|
||||
self.load_market_data().await?;
|
||||
|
||||
eprintln!("Event queue empty: {}, length: {}", self.event_queue.read().is_empty(), self.event_queue.read().len());
|
||||
eprintln!("Current time: {}, End time: {}", self.time_provider.now(), self.config.end_time);
|
||||
|
||||
// Main event loop
|
||||
while !self.event_queue.read().is_empty() ||
|
||||
self.time_provider.now() < self.config.end_time
|
||||
{
|
||||
// Get next batch of events
|
||||
let current_time = self.time_provider.now();
|
||||
let events = self.event_queue.write().pop_until(current_time);
|
||||
|
||||
for event in events {
|
||||
self.process_event(event).await?;
|
||||
let mut iteration = 0;
|
||||
while !self.event_queue.read().is_empty() {
|
||||
iteration += 1;
|
||||
if iteration <= 5 || iteration % 100 == 0 {
|
||||
eprintln!("Processing iteration {} at time {}", iteration, self.time_provider.now());
|
||||
}
|
||||
|
||||
// Update portfolio value
|
||||
self.update_portfolio_value();
|
||||
|
||||
// Check if we should advance time
|
||||
if self.event_queue.read().is_empty() {
|
||||
// Advance to next data point or end time
|
||||
if let Some(next_time) = self.get_next_event_time() {
|
||||
if next_time < self.config.end_time {
|
||||
self.advance_time(next_time);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
// Get the next event's timestamp
|
||||
let next_event_time = self.event_queue.read()
|
||||
.peek_next()
|
||||
.map(|e| e.timestamp);
|
||||
|
||||
if let Some(event_time) = next_event_time {
|
||||
// Advance time to the next event
|
||||
self.advance_time(event_time);
|
||||
|
||||
// Get all events at this timestamp
|
||||
let current_time = self.time_provider.now();
|
||||
let events = self.event_queue.write().pop_until(current_time);
|
||||
|
||||
for event in events {
|
||||
self.process_event(event).await?;
|
||||
}
|
||||
|
||||
// Update portfolio value
|
||||
self.update_portfolio_value();
|
||||
} else {
|
||||
// No more events
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
eprintln!("Backtest complete. Total trades: {}", self.total_trades);
|
||||
|
||||
// Generate results
|
||||
Ok(self.generate_results())
|
||||
}
|
||||
|
||||
async fn load_market_data(&mut self) -> Result<(), String> {
|
||||
eprintln!("load_market_data: Starting");
|
||||
let mut data_source = self.market_data_source.write();
|
||||
|
||||
eprintln!("load_market_data: Seeking to start time: {}", self.config.start_time);
|
||||
// Seek to start time
|
||||
data_source.seek_to_time(self.config.start_time)?;
|
||||
|
||||
eprintln!("load_market_data: Loading data");
|
||||
let mut count = 0;
|
||||
// Load all data into event queue
|
||||
while let Some(update) = data_source.get_next_update().await {
|
||||
if update.timestamp > self.config.end_time {
|
||||
break;
|
||||
}
|
||||
|
||||
count += 1;
|
||||
if count % 100 == 0 {
|
||||
eprintln!("load_market_data: Loaded {} data points", count);
|
||||
}
|
||||
|
||||
let event = BacktestEvent::market_data(update.timestamp, update);
|
||||
self.event_queue.write().push(event);
|
||||
}
|
||||
|
||||
eprintln!("load_market_data: Complete. Loaded {} total data points", count);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -391,8 +409,10 @@ impl BacktestEngine {
|
|||
}
|
||||
|
||||
fn get_next_event_time(&self) -> Option<DateTime<Utc>> {
|
||||
// In a real implementation, this would look at the next market data point
|
||||
None
|
||||
// Get the timestamp of the next event in the queue
|
||||
self.event_queue.read()
|
||||
.peek_next()
|
||||
.map(|event| event.timestamp)
|
||||
}
|
||||
|
||||
fn generate_results(&self) -> BacktestResult {
|
||||
|
|
|
|||
|
|
@ -109,4 +109,8 @@ impl EventQueue {
|
|||
pub fn len(&self) -> usize {
|
||||
self.events.len()
|
||||
}
|
||||
|
||||
pub fn peek_next(&self) -> Option<&BacktestEvent> {
|
||||
self.events.front()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue