finished initial backtest / engine
This commit is contained in:
parent
55b4ca78c9
commit
c106a719e8
18 changed files with 1571 additions and 180 deletions
|
|
@ -74,7 +74,10 @@ export abstract class BaseStrategy extends EventEmitter {
|
|||
|
||||
// Market data handling
|
||||
async onMarketData(data: MarketData): Promise<void> {
|
||||
if (!this.isActive) return;
|
||||
if (!this.isActive) {
|
||||
logger.info(`[BaseStrategy] Strategy ${this.config.id} received market data but is not active`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Update any indicators or state
|
||||
|
|
@ -210,20 +213,27 @@ export abstract class BaseStrategy extends EventEmitter {
|
|||
// Check if we already have a position
|
||||
const currentPosition = this.getPosition(signal.symbol);
|
||||
|
||||
// Use quantity from signal metadata if provided
|
||||
const quantity = signal.metadata?.quantity || this.calculatePositionSize(signal);
|
||||
|
||||
logger.info(`[BaseStrategy] Converting signal to order: ${signal.type} ${quantity} ${signal.symbol}, current position: ${currentPosition}`);
|
||||
|
||||
// Simple logic - can be overridden by specific strategies
|
||||
if (signal.type === 'buy' && currentPosition <= 0) {
|
||||
if (signal.type === 'buy') {
|
||||
// Allow buying to open long or close short
|
||||
return {
|
||||
symbol: signal.symbol,
|
||||
side: 'buy',
|
||||
quantity: this.calculatePositionSize(signal),
|
||||
quantity: quantity,
|
||||
orderType: 'market',
|
||||
timeInForce: 'DAY'
|
||||
};
|
||||
} else if (signal.type === 'sell' && currentPosition >= 0) {
|
||||
} else if (signal.type === 'sell') {
|
||||
// Allow selling to close long or open short
|
||||
return {
|
||||
symbol: signal.symbol,
|
||||
side: 'sell',
|
||||
quantity: this.calculatePositionSize(signal),
|
||||
quantity: quantity,
|
||||
orderType: 'market',
|
||||
timeInForce: 'DAY'
|
||||
};
|
||||
|
|
|
|||
|
|
@ -163,6 +163,12 @@ export class StrategyManager extends EventEmitter {
|
|||
|
||||
private async handleMarketData(data: MarketData): Promise<void> {
|
||||
// Forward to all active strategies
|
||||
if (this.activeStrategies.size === 0) {
|
||||
this.container.logger.info(`[StrategyManager] No active strategies to process market data! All strategies: ${Array.from(this.strategies.keys()).join(', ')}`);
|
||||
} else {
|
||||
this.container.logger.info(`[StrategyManager] Forwarding market data to ${this.activeStrategies.size} active strategies: ${Array.from(this.activeStrategies).join(', ')}`);
|
||||
}
|
||||
|
||||
for (const strategyId of this.activeStrategies) {
|
||||
const strategy = this.strategies.get(strategyId);
|
||||
if (strategy) {
|
||||
|
|
@ -267,6 +273,10 @@ export class StrategyManager extends EventEmitter {
|
|||
getStrategy(strategyId: string): BaseStrategy | undefined {
|
||||
return this.strategies.get(strategyId);
|
||||
}
|
||||
|
||||
getAllStrategies(): BaseStrategy[] {
|
||||
return Array.from(this.strategies.values());
|
||||
}
|
||||
|
||||
async shutdown(): Promise<void> {
|
||||
this.container.logger.info('Shutting down strategy manager...');
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ const logger = getLogger('SimpleMovingAverageCrossover');
|
|||
export class SimpleMovingAverageCrossover extends BaseStrategy {
|
||||
private priceHistory = new Map<string, number[]>();
|
||||
private lastTradeTime = new Map<string, number>();
|
||||
private barCount = new Map<string, number>();
|
||||
private totalSignals = 0;
|
||||
|
||||
// Strategy parameters
|
||||
|
|
@ -30,12 +31,17 @@ export class SimpleMovingAverageCrossover extends BaseStrategy {
|
|||
// Update price history
|
||||
if (!this.priceHistory.has(symbol)) {
|
||||
this.priceHistory.set(symbol, []);
|
||||
this.barCount.set(symbol, 0);
|
||||
logger.info(`📊 Starting to track ${symbol} @ ${price}`);
|
||||
}
|
||||
|
||||
const history = this.priceHistory.get(symbol)!;
|
||||
history.push(price);
|
||||
|
||||
// Increment bar count
|
||||
const currentBar = (this.barCount.get(symbol) || 0) + 1;
|
||||
this.barCount.set(symbol, currentBar);
|
||||
|
||||
// Keep only needed history
|
||||
if (history.length > this.SLOW_PERIOD * 2) {
|
||||
history.shift();
|
||||
|
|
@ -74,8 +80,9 @@ export class SimpleMovingAverageCrossover extends BaseStrategy {
|
|||
const timestamp = new Date(data.data.timestamp).toISOString().split('T')[0];
|
||||
|
||||
// Check minimum holding period
|
||||
const currentBar = this.barCount.get(symbol) || 0;
|
||||
const lastTradeBar = this.lastTradeTime.get(symbol) || 0;
|
||||
const barsSinceLastTrade = lastTradeBar > 0 ? history.length - lastTradeBar : Number.MAX_SAFE_INTEGER;
|
||||
const barsSinceLastTrade = lastTradeBar > 0 ? currentBar - lastTradeBar : Number.MAX_SAFE_INTEGER;
|
||||
|
||||
// Detect crossovers FIRST
|
||||
const goldenCross = prevFastMA <= prevSlowMA && fastMA > slowMA;
|
||||
|
|
@ -87,7 +94,7 @@ export class SimpleMovingAverageCrossover extends BaseStrategy {
|
|||
const masAreClose = Math.abs(maDiffPct) < 1.0; // Within 1%
|
||||
|
||||
if (history.length % this.DEBUG_INTERVAL === 0 || masAreClose || goldenCross || deathCross) {
|
||||
logger.info(`${symbol} @ ${timestamp} [Bar ${history.length}]:`);
|
||||
logger.info(`${symbol} @ ${timestamp} [Bar ${currentBar}]:`);
|
||||
logger.info(` Price: $${currentPrice.toFixed(2)}`);
|
||||
logger.info(` Fast MA (${this.FAST_PERIOD}): $${fastMA.toFixed(2)}`);
|
||||
logger.info(` Slow MA (${this.SLOW_PERIOD}): $${slowMA.toFixed(2)}`);
|
||||
|
|
@ -131,7 +138,7 @@ export class SimpleMovingAverageCrossover extends BaseStrategy {
|
|||
}
|
||||
};
|
||||
|
||||
this.lastTradeTime.set(symbol, history.length);
|
||||
this.lastTradeTime.set(symbol, currentBar);
|
||||
this.totalSignals++;
|
||||
logger.info(`👉 Total signals generated: ${this.totalSignals}`);
|
||||
return signal;
|
||||
|
|
@ -160,7 +167,7 @@ export class SimpleMovingAverageCrossover extends BaseStrategy {
|
|||
}
|
||||
};
|
||||
|
||||
this.lastTradeTime.set(symbol, history.length);
|
||||
this.lastTradeTime.set(symbol, currentBar);
|
||||
this.totalSignals++;
|
||||
logger.info(`👉 Total signals generated: ${this.totalSignals}`);
|
||||
return signal;
|
||||
|
|
@ -194,7 +201,7 @@ export class SimpleMovingAverageCrossover extends BaseStrategy {
|
|||
}
|
||||
};
|
||||
|
||||
this.lastTradeTime.set(symbol, history.length);
|
||||
this.lastTradeTime.set(symbol, currentBar);
|
||||
this.totalSignals++;
|
||||
logger.info(`👉 Total signals generated: ${this.totalSignals}`);
|
||||
return signal;
|
||||
|
|
@ -222,7 +229,7 @@ export class SimpleMovingAverageCrossover extends BaseStrategy {
|
|||
}
|
||||
};
|
||||
|
||||
this.lastTradeTime.set(symbol, history.length);
|
||||
this.lastTradeTime.set(symbol, currentBar);
|
||||
this.totalSignals++;
|
||||
logger.info(`👉 Total signals generated: ${this.totalSignals}`);
|
||||
return signal;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue