From 5f8d78c7ae07b2dc0e1be422f0c7bb9c2b1ce69f Mon Sep 17 00:00:00 2001 From: Marco Ellwanger Date: Tue, 14 Jan 2025 15:45:50 -0800 Subject: [PATCH 1/2] fix hanging backtest when using take profit or stop loss orders --- src/broker.ts | 2 +- test/sma-cross.strategy.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/broker.ts b/src/broker.ts index 95051b3..89ae530 100644 --- a/src/broker.ts +++ b/src/broker.ts @@ -124,7 +124,7 @@ export class Broker { const prevClose = first(data['close'].values.slice(-2)) as number; let reprocessOrders = false; - for (let i = 0; i < this.orders.length; i = 0) { + for (let i = 0; i < this.orders.length; i++) { const order = this.orders[i]; /* istanbul ignore if */ diff --git a/test/sma-cross.strategy.ts b/test/sma-cross.strategy.ts index 73a2a13..bf973cb 100644 --- a/test/sma-cross.strategy.ts +++ b/test/sma-cross.strategy.ts @@ -33,7 +33,8 @@ export class SmaCross extends Strategy { next(ctx: Context) { const { index, signals } = ctx; if (index < this.params.n1 || index < this.params.n2) return; - if (signals.get('crossUp')) this.buy({ size: 1000 }); + const price = ctx.data['close']; + if (signals.get('crossUp')) this.buy({ size: 1000, tpPrice: price * 1.15, slPrice: price * 0.9 }); if (signals.get('crossDown')) this.sell({ size: 1000 }); } } From d59b97ae438d8f131e0976647cc0df26c57292a0 Mon Sep 17 00:00:00 2001 From: Marco Ellwanger Date: Thu, 16 Jan 2025 15:20:46 -0800 Subject: [PATCH 2/2] Feature: allow user-defined trade execution price --- src/broker.ts | 8 ++++---- src/interfaces/order-options.interface.ts | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/broker.ts b/src/broker.ts index 89ae530..8cc2dfb 100644 --- a/src/broker.ts +++ b/src/broker.ts @@ -61,9 +61,9 @@ export class Broker { } public newOrder(options: OrderOptions) { - const { size, stopPrice, limitPrice, slPrice, tpPrice, parentTrade } = options; + const { price, size, stopPrice, limitPrice, slPrice, tpPrice, parentTrade } = options; const isLong = size > 0; - const adjustedPrice = this.adjustPrice({ size }); + const adjustedPrice = this.adjustPrice({ price, size }); if (isLong) { if (!((limitPrice || stopPrice || adjustedPrice) > (slPrice || Number.NEGATIVE_INFINITY) && (limitPrice || stopPrice || adjustedPrice) < (tpPrice || Number.POSITIVE_INFINITY))) { @@ -232,8 +232,8 @@ export class Broker { } /** - * Long/short `price`, adjusted for commisions. - * In long positions, the adjusted price is a fraction higher, and vice versa. + * Long/short `price`, adjusted for commissions or user-defined trade execution price. + * In long positions, the commission-adjusted price for is a fraction higher, and vice versa. */ private adjustPrice(options: { size: number, price?: number }) { const { size, price } = options; diff --git a/src/interfaces/order-options.interface.ts b/src/interfaces/order-options.interface.ts index 113918a..7c6c679 100644 --- a/src/interfaces/order-options.interface.ts +++ b/src/interfaces/order-options.interface.ts @@ -1,6 +1,7 @@ import { Trade } from '../trade'; export interface OrderOptions { + price?: number; size: number; limitPrice?: number; stopPrice?: number;