Backtest your strategy

In simple words, backtesting a trading strategy is the process of testing a trading hypothesis/strategy on prior time periods.

Cassandre trading bot allows you to simulate your bots' reaction to historical data during tests.

The first step is to add cassandre-trading-bot-spring-boot-starter-test to your project dependency.

Edit your pom.xml file and add :

<dependencies>
...
<dependency>
<groupId>tech.cassandre.trading.bot</groupId>
<artifactId>cassandre-trading-bot-spring-boot-starter-test</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
...
</dependencies>

Maven Central

The second step is to set the cassandretrading.bot.exchange.modes.dry parameter to true: this will make Cassandre simulate the exchange, it will simulate buying/selling orders and will increase/decrease your account.

Now, we need to generate the data you want to use during your JUnit tests. To do so, you can run this on the command line (on Linux) :

startDate=`date --date="3 months ago" +"%s"`
endDate=`date +"%s"`
curl -s "https://api.kucoin.com/api/v1/market/candles?type=1day&symbol=BTC-USDT&startAt=${startDate}&endAt=${endDate}" \
| jq -r -c ".data[] | @tsv" \
| tac $1 > tickers-btc-usdt.tsv

It will create a file named tickers-btc-usdt.tsv that contains the historical rate of btc-usdt from startDate (3 months ago) to endDate (now). Of course, you can change dates and currency pairs.

Now place this file in the src/test/resources folder of our project and add this line to your JUnit test class:

@Import(TickerFluxMock.class)

Now, instead of receiving tickers from the exchange, you will receive tickers imported from the tsv/csv files you put in src/test/resources.

Your test is in src/test/java/com/SimpleTa4jStrategyTest.java.

Now we write the tests :

@Test
@DisplayName("Check gains")
public void gainTest() {
await().forever().until(() -> tickerFluxMock.isFluxDone());
final HashMap<CurrencyDTO, GainDTO> gains = strategy.getPositionService().getGains();
System.out.println("Cumulated gains:");
gains.forEach((currency, gain) -> System.out.println(currency + " : " + gain.getAmount()));
System.out.println("Position still opened :");
strategy.getPositions()
.values()
.stream()
.filter(p -> p.getStatus().equals(OPENED))
.forEach(p -> System.out.println(" - " + p));
assertTrue(gains.get(strategy.getRequestedCurrencyPair().getQuoteCurrency()).getPercentage() > 0);
}

The first thing we do with the await() method is to wait until all data from btc-usdt.csv are imported.

Then, we calculate the gains of every closed position and we check that the gains are superior to zero.

The last thing we do is to display the list of positions that are not closed.