From d7adb6cf92c2cda90f89d7702e7b49dd623c4791 Mon Sep 17 00:00:00 2001 From: Marco Ellwanger Date: Mon, 27 Jan 2025 16:07:05 -0800 Subject: [PATCH] Add openBrowser and outputFile to backtest options for passthrough --- src/backtest.ts | 4 +++- src/interfaces/backtest-options.interface.ts | 2 ++ src/interfaces/broker-options.interface.ts | 2 +- src/interfaces/stats-options.interface.ts | 2 ++ src/plotting.ts | 4 ++-- src/stats.ts | 3 ++- 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/backtest.ts b/src/backtest.ts index e136c74..dd60208 100644 --- a/src/backtest.ts +++ b/src/backtest.ts @@ -63,6 +63,8 @@ export class Backtest { tradeOnClose: false, hedging: false, exclusiveOrders: false, + outputFile: '', + openBrowser: true, ...this.options, }); const strategy = new this.Strategy(data, broker); @@ -85,7 +87,7 @@ export class Backtest { strategy, new Series(broker.equities), broker.closedTrades as Trade[], - { riskFreeRate: 0 }, + { riskFreeRate: 0, filename: this.options?.outputFile, openBrowser: this.options?.openBrowser }, ).compute(); this._stats = stats; diff --git a/src/interfaces/backtest-options.interface.ts b/src/interfaces/backtest-options.interface.ts index ffe2e0e..82d52ca 100644 --- a/src/interfaces/backtest-options.interface.ts +++ b/src/interfaces/backtest-options.interface.ts @@ -5,4 +5,6 @@ export interface BacktestOptions { tradeOnClose?: boolean; hedging?: boolean; exclusiveOrders?: boolean; + outputFile?: string; + openBrowser?: boolean; } diff --git a/src/interfaces/broker-options.interface.ts b/src/interfaces/broker-options.interface.ts index 39986cf..9d0ce62 100644 --- a/src/interfaces/broker-options.interface.ts +++ b/src/interfaces/broker-options.interface.ts @@ -1,3 +1,3 @@ import { BacktestOptions } from './backtest-options.interface'; -export interface BrokerOptions extends Required {} +export interface BrokerOptions extends Required> {} diff --git a/src/interfaces/stats-options.interface.ts b/src/interfaces/stats-options.interface.ts index b5ca6ac..90a81a3 100644 --- a/src/interfaces/stats-options.interface.ts +++ b/src/interfaces/stats-options.interface.ts @@ -2,4 +2,6 @@ export interface StatsOptions { riskFreeRate?: number; precision?: number; digits?: number; + filename?: string; + openBrowser?: boolean; } diff --git a/src/plotting.ts b/src/plotting.ts index 55168ce..6629974 100644 --- a/src/plotting.ts +++ b/src/plotting.ts @@ -13,7 +13,7 @@ export class Plotting { constructor(private readonly stats: Stats, private readonly options?: PlottingOptions) { this.openBrowser = options?.openBrowser ?? true; - this.filename = options?.filename ?? 'output.html'; + this.filename = options?.filename?.toLowerCase() ?? 'output.html'; } public plot() { @@ -26,7 +26,7 @@ export class Plotting { removeOptionalTags: true, minifyJS: true }); - const outputFile = `./${this.filename}`; + const outputFile = this.filename.endsWith('.html') ? `./${this.filename}` : `./${this.filename}.html`; fs.writeFileSync(outputFile, html); if (this.openBrowser) open(outputFile); diff --git a/src/stats.ts b/src/stats.ts index 18b189c..112ed92 100644 --- a/src/stats.ts +++ b/src/stats.ts @@ -176,7 +176,7 @@ export class Stats { if (!this.results) { throw new Error('No stats results'); } - new Plotting(this).plot(); + new Plotting(this, { openBrowser: this.options.openBrowser, filename: this.options.filename }).plot(); } private computeExposureTime(index: string[], tradeLog: DataFrame) { @@ -267,6 +267,7 @@ export class Stats { private computeGeometricMean(returns: Series) { returns = returns.fillNa(0).add(1) as Series; /* istanbul ignore next */ + // @ts-ignore if (returns.values.some(v => v <= 0)) return 0; /* istanbul ignore next */ return Math.exp(returns.apply(v => Math.log(v)).sum() / (returns.values.length || 0)) - 1;