Skip to content

Commit b813d4a

Browse files
committed
provide current position also inside backtest
1 parent a6509a9 commit b813d4a

File tree

6 files changed

+80
-12
lines changed

6 files changed

+80
-12
lines changed

src/dict/position.js

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ module.exports = class Position {
3232
this.raw = raw;
3333
}
3434

35+
getSide() {
36+
return this.side;
37+
}
38+
3539
isShort() {
3640
return this.side === 'short';
3741
}

src/dict/strategy_context.js

+21-3
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,36 @@ module.exports = class StrategyContext {
66
this.lastSignal = undefined;
77
this.amount = undefined;
88
this.entry = undefined;
9+
this.profit = undefined;
910
}
1011

1112
static createFromPosition(ticker, position) {
1213
const context = new StrategyContext(ticker);
1314

14-
context.amount = position.amount;
15-
context.lastSignal = position.amount < 0 ? 'short' : 'long';
16-
context.entry = position.entry;
15+
context.amount = position.getAmount();
16+
context.lastSignal = position.getSide();
17+
context.entry = position.getEntry();
18+
context.profit = position.getProfit();
1719

1820
return context;
1921
}
2022

23+
getAmount() {
24+
return this.amount;
25+
}
26+
27+
getLastSignal() {
28+
return this.lastSignal;
29+
}
30+
31+
getEntry() {
32+
return this.entry;
33+
}
34+
35+
getProfit() {
36+
return this.profit;
37+
}
38+
2139
static create(ticker) {
2240
return new StrategyContext(ticker);
2341
}

src/modules/backtest.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const moment = require('moment');
22
const _ = require('lodash');
33
const StrategyManager = require('./strategy/strategy_manager');
44
const Resample = require('../utils/resample');
5+
const CommonUtil = require('../utils/common_util');
56

67
module.exports = class Backtest {
78
constructor(instances, strategyManager, exchangeCandleCombine, projectDir) {
@@ -101,7 +102,8 @@ module.exports = class Backtest {
101102
exchange,
102103
pair,
103104
options,
104-
lastSignal.signal
105+
lastSignal.signal,
106+
lastSignal.price
105107
);
106108
item.time = current;
107109

@@ -112,10 +114,8 @@ module.exports = class Backtest {
112114
}
113115

114116
// position profit
115-
if (lastSignal.signal === 'long' && lastSignal.price) {
116-
item.profit = parseFloat(((item.price / lastSignal.price - 1) * 100).toFixed(2));
117-
} else if (lastSignal.signal === 'short' && lastSignal.price) {
118-
item.profit = parseFloat(((lastSignal.price / item.price - 1) * 100).toFixed(2));
117+
if (lastSignal.price) {
118+
item.profit = CommonUtil.getProfitAsPercent(lastSignal.signal, item.price, lastSignal.price);
119119
}
120120

121121
if (['long', 'short'].includes(currentSignal)) {

src/modules/strategy/dict/indicator_period.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@ module.exports = class IndicatorPeriod {
99
}
1010

1111
getLastSignal() {
12-
if (!this.strategyContext || !this.strategyContext.lastSignal) {
12+
if (!this.strategyContext || !this.strategyContext.getLastSignal()) {
1313
return undefined;
1414
}
1515

16-
return this.strategyContext.lastSignal;
16+
return this.strategyContext.getLastSignal();
17+
}
18+
19+
getProfit() {
20+
return this.strategyContext.getProfit();
1721
}
1822

1923
/**

src/modules/strategy/strategy_manager.js

+25-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ const IndicatorBuilder = require('./dict/indicator_builder');
55
const IndicatorPeriod = require('./dict/indicator_period');
66
const ta = require('../../utils/technical_analysis');
77
const Resample = require('../../utils/resample');
8+
const CommonUtil = require('../../utils/common_util');
89
const StrategyContext = require('../../dict/strategy_context');
910
const Ticker = require('../../dict/ticker');
1011
const SignalResult = require('./dict/signal_result');
12+
const Position = require('../../dict/position');
1113

1214
module.exports = class StrategyManager {
1315
constructor(technicalAnalysisValidator, exchangeCandleCombine, logger, projectDir) {
@@ -94,16 +96,37 @@ module.exports = class StrategyManager {
9496
* @param symbol
9597
* @param options
9698
* @param lastSignal
99+
* @param lastSignalEntry
97100
* @returns {Promise<array>}
98101
*/
99-
async executeStrategyBacktest(strategyName, exchange, symbol, options, lastSignal) {
102+
async executeStrategyBacktest(strategyName, exchange, symbol, options, lastSignal, lastSignalEntry) {
100103
const results = await this.getTaResult(strategyName, exchange, symbol, options);
101104
if (!results || Object.keys(results).length === 0) {
102105
return {};
103106
}
104107

105108
const price = results._candle ? results._candle.close : undefined;
106-
const context = StrategyContext.create(new Ticker(exchange, symbol, undefined, price, price));
109+
110+
let context;
111+
if (lastSignal && lastSignalEntry && price) {
112+
// provide a suitable value; its just backtesting
113+
const amount = lastSignal === 'short' ? -1 : 1;
114+
115+
context = StrategyContext.createFromPosition(
116+
new Ticker(exchange, symbol, undefined, price, price),
117+
new Position(
118+
symbol,
119+
lastSignal,
120+
amount,
121+
CommonUtil.getProfitAsPercent(lastSignal, price, lastSignalEntry),
122+
undefined,
123+
lastSignalEntry
124+
)
125+
);
126+
} else {
127+
context = StrategyContext.create(new Ticker(exchange, symbol, undefined, price, price));
128+
}
129+
107130
context.lastSignal = lastSignal;
108131

109132
const indicatorPeriod = new IndicatorPeriod(context, results);

src/utils/common_util.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module.exports = {
2+
/**
3+
*
4+
* @param {string} side
5+
* @param {number} currentPrice
6+
* @param {number} entryPrice
7+
* @returns {number}
8+
*/
9+
getProfitAsPercent: (side, currentPrice, entryPrice) => {
10+
switch (side) {
11+
case 'long':
12+
return parseFloat(((currentPrice / entryPrice - 1) * 100).toFixed(2));
13+
case 'short':
14+
return parseFloat(((entryPrice / currentPrice - 1) * 100).toFixed(2));
15+
default:
16+
throw new Error(`Invalid direction given for profit ${side}`);
17+
}
18+
}
19+
};

0 commit comments

Comments
 (0)