import { BacktestEngine } from '@stock-bot/engine'; import { MarketData } from '../types'; export interface Signal { symbol: string; signal_type: 'Buy' | 'Sell' | 'Close'; strength: number; // -1.0 to 1.0 quantity?: number; reason?: string; metadata?: any; } export interface StrategyCall { method: string; data: any; } export interface StrategyResponse { signals: Signal[]; } /** * Base class for TypeScript strategies that run in the Rust backtest engine */ export abstract class RustStrategy { protected name: string; protected id: string; protected parameters: Record; protected positions: Map = new Map(); constructor(name: string, id: string, parameters: Record = {}) { this.name = name; this.id = id; this.parameters = parameters; } /** * Main callback that Rust will call */ public handleCall(call: StrategyCall): StrategyResponse { switch (call.method) { case 'on_market_data': const signals = this.onMarketData(call.data); return { signals }; case 'on_fill': this.onFill( call.data.symbol, call.data.quantity, call.data.price, call.data.side ); return { signals: [] }; default: return { signals: [] }; } } /** * Called when new market data is received */ protected abstract onMarketData(data: MarketData): Signal[]; /** * Called when an order is filled */ protected onFill(symbol: string, quantity: number, price: number, side: string): void { const currentPosition = this.positions.get(symbol) || 0; const newPosition = side === 'buy' ? currentPosition + quantity : currentPosition - quantity; if (Math.abs(newPosition) < 0.0001) { this.positions.delete(symbol); } else { this.positions.set(symbol, newPosition); } } /** * Helper to create a buy signal */ protected buySignal(symbol: string, strength: number = 1.0, reason?: string): Signal { return { symbol, signal_type: 'Buy', strength, reason, }; } /** * Helper to create a sell signal */ protected sellSignal(symbol: string, strength: number = 1.0, reason?: string): Signal { return { symbol, signal_type: 'Sell', strength, reason, }; } /** * Helper to create a close position signal */ protected closeSignal(symbol: string, reason?: string): Signal { return { symbol, signal_type: 'Close', strength: 1.0, reason, }; } /** * Register this strategy with a backtest engine */ public register(engine: BacktestEngine): void { console.log(`Registering strategy ${this.name} with id ${this.id}`); // Convert the handleCall method to what Rust expects const callback = (callJson: string) => { console.log('Strategy callback called with:', callJson); const call: StrategyCall = JSON.parse(callJson); const response = this.handleCall(call); console.log('Strategy response:', response); return JSON.stringify(response); }; engine.addTypescriptStrategy( this.name, this.id, this.parameters, callback as any ); } }