forked from ta4j/ta4j
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSimpleMovingAverageRangeBacktest.java
More file actions
158 lines (142 loc) · 6.68 KB
/
Copy pathSimpleMovingAverageRangeBacktest.java
File metadata and controls
158 lines (142 loc) · 6.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
* SPDX-License-Identifier: MIT
*/
package ta4jexamples.backtesting;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.ta4j.core.*;
import org.ta4j.core.backtest.BacktestExecutionResult;
import org.ta4j.core.backtest.BacktestExecutor;
import org.ta4j.core.backtest.TradingStatementExecutionResult.WeightedCriterion;
import org.ta4j.core.criteria.drawdown.ReturnOverMaxDrawdownCriterion;
import org.ta4j.core.criteria.pnl.NetProfitCriterion;
import org.ta4j.core.indicators.averages.SMAIndicator;
import org.ta4j.core.indicators.helpers.ClosePriceIndicator;
import org.ta4j.core.num.DecimalNum;
import org.ta4j.core.num.Num;
import org.ta4j.core.reports.BasePerformanceReport;
import org.ta4j.core.reports.PositionStatsReport;
import org.ta4j.core.reports.TradingStatement;
import org.ta4j.core.rules.OverIndicatorRule;
import org.ta4j.core.rules.UnderIndicatorRule;
import ta4jexamples.datasources.CsvFileBarSeriesDataSource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Example demonstrating how to use {@link BacktestExecutor} for parallel
* strategy evaluation.
*
* This example:
* <ul>
* <li>Creates multiple variations of a Simple Moving Average (SMA)
* strategy.</li>
* <li>Uses {@code BacktestExecutor} to run them in parallel over the data
* series.</li>
* <li>Ranks the strategies based on a composite {@link WeightedCriterion}.</li>
* <li>Prints a performance report for the best strategies.</li>
* </ul>
*/
public class SimpleMovingAverageRangeBacktest {
private static final Logger LOG = LogManager.getLogger(SimpleMovingAverageRangeBacktest.class);
private static final int DEFAULT_TOP_STRATEGIES = 3;
public static void main(String[] args) {
BarSeries series = CsvFileBarSeriesDataSource.loadSeriesFromFile();
int start = 3;
int stop = 50;
int step = 5;
final List<Strategy> strategies = new ArrayList<>();
for (int i = start; i <= stop; i += step) {
Strategy strategy = new BaseStrategy("Sma(" + i + ")", createEntryRule(series, i),
createExitRule(series, i));
strategies.add(strategy);
}
BacktestExecutor backtestExecutor = new BacktestExecutor(series);
BacktestExecutionResult result = backtestExecutor.executeWithRuntimeReport(strategies, DecimalNum.valueOf(50),
Trade.TradeType.BUY);
List<TradingStatement> tradingStatements = selectTopStrategies(result, DEFAULT_TOP_STRATEGIES);
LOG.debug("Top {} weighted SMA strategies (7 parts net profit, 3 parts return over max drawdown)",
tradingStatements.size());
LOG.debug(printReport(tradingStatements));
}
/**
* Selects the top strategies for this example using weighted, normalized
* ranking.
*
* @param result full backtest result for the SMA parameter sweep
* @param limit maximum number of strategies to keep
* @return top strategies ordered by the example weighted criteria
*/
static List<TradingStatement> selectTopStrategies(BacktestExecutionResult result, int limit) {
Objects.requireNonNull(result, "result cannot be null");
return result.getTopStrategiesWeighted(limit, WeightedCriterion.of(new NetProfitCriterion(), 7.0),
WeightedCriterion.of(new ReturnOverMaxDrawdownCriterion(), 3.0));
}
private static Rule createEntryRule(BarSeries series, int barCount) {
Indicator<Num> closePrice = new ClosePriceIndicator(series);
SMAIndicator sma = new SMAIndicator(closePrice, barCount);
return new UnderIndicatorRule(sma, closePrice);
}
private static Rule createExitRule(BarSeries series, int barCount) {
Indicator<Num> closePrice = new ClosePriceIndicator(series);
SMAIndicator sma = new SMAIndicator(closePrice, barCount);
return new OverIndicatorRule(sma, closePrice);
}
private static String printReport(List<TradingStatement> tradingStatements) {
StringBuilder resultBuilder = new StringBuilder();
resultBuilder.append(System.lineSeparator());
for (TradingStatement statement : tradingStatements) {
resultBuilder.append(printStatementReport(statement));
resultBuilder.append(System.lineSeparator());
}
return resultBuilder.toString();
}
private static StringBuilder printStatementReport(TradingStatement statement) {
StringBuilder resultBuilder = new StringBuilder();
resultBuilder.append("######### ")
.append(statement.getStrategy().getName())
.append(" #########")
.append(System.lineSeparator())
.append(printPerformanceReport(statement.getPerformanceReport()))
.append(System.lineSeparator())
.append(printPositionStats(statement.getPositionStatsReport()))
.append(System.lineSeparator())
.append("###########################");
return resultBuilder;
}
private static StringBuilder printPerformanceReport(BasePerformanceReport report) {
StringBuilder resultBuilder = new StringBuilder();
resultBuilder.append("--------- performance report ---------")
.append(System.lineSeparator())
.append("total loss: ")
.append(report.totalLoss)
.append(System.lineSeparator())
.append("total profit: ")
.append(report.totalProfit)
.append(System.lineSeparator())
.append("total profit loss: ")
.append(report.totalProfitLoss)
.append(System.lineSeparator())
.append("total profit loss percentage: ")
.append(report.totalProfitLossPercentage)
.append(System.lineSeparator())
.append("---------------------------");
return resultBuilder;
}
private static StringBuilder printPositionStats(PositionStatsReport report) {
StringBuilder resultBuilder = new StringBuilder();
resultBuilder.append("--------- trade statistics report ---------")
.append(System.lineSeparator())
.append("loss trade count: ")
.append(report.getLossCount())
.append(System.lineSeparator())
.append("profit trade count: ")
.append(report.getProfitCount())
.append(System.lineSeparator())
.append("break even trade count: ")
.append(report.getBreakEvenCount())
.append(System.lineSeparator())
.append("---------------------------");
return resultBuilder;
}
}