Strategy
Description
Binance4j-strategy adds technical analysis for the binance4j ecosystem.
Installation
- Maven
- Gradle
<dependency>
<groupId>{{groupId}}</groupId>
<artifactId>{{artifactId}}</artifactId>
<version>{{version}}</version>
</dependency>
implementation '{{groupId}}:{{artifactId}}:{{version}}'
Dependencies
- binance4j-core : The core of every binance4j artifact
- binance4j-vision : Retrieve Binance public data
- binance4j-websocket : Real-time market streams
- Lombok : Prevent boilerplate code.
- OkHttp : HTTP && Websocket clients
- Retrofit : Map API endpoints with annotations.
- Jackson : Payload deserialization
- Apache Common Codecs : Encode/decode urls
Write a strategy
Binance4j uses ta4j for technical analysis and backtesting.
To understand how indicators and rules work, read the library documentation
//Every Strategy must extend BaseTradingStrategy
public class TwoPeriodRSIStrategy extends BaseTradingStrategy {
//This is where we define the rule that will send a BUY signal
@Override
public Rule getEntry(BarSeries series) {
ClosePriceIndicator closePrice = new ClosePriceIndicator(series);
SMAIndicator shortSma = new SMAIndicator(closePrice, 5);
SMAIndicator longSma = new SMAIndicator(closePrice, 200);
// We use a 2-period RSI indicator to identify buying
// or selling opportunities within the bigger trend.
RSIIndicator rsi = new RSIIndicator(closePrice, 2);
// Entry rule
// The long-term trend is up when a security is above its 200-period SMA.
return new OverIndicatorRule(shortSma, longSma) // Trend
.and(new CrossedDownIndicatorRule(rsi, 5)) // Signal 1
.and(new OverIndicatorRule(shortSma, closePrice)); // Signal 2
}
//This is where we define the rule that will send a SELL signal
@Override
public Rule getExit(BarSeries series) {
ClosePriceIndicator closePrice = new ClosePriceIndicator(series);
SMAIndicator shortSma = new SMAIndicator(closePrice, 5);
SMAIndicator longSma = new SMAIndicator(closePrice, 200);
// We use a 2-period RSI indicator to identify buying
// or selling opportunities within the bigger trend.
RSIIndicator rsi = new RSIIndicator(closePrice, 2);
// Exit rule
// The long-term trend is down when a security is below its 200-period SMA.
return new UnderIndicatorRule(shortSma, longSma) // Trend
.and(new CrossedUpIndicatorRule(rsi, 95)) // Signal 1
.and(new UnderIndicatorRule(shortSma, closePrice)); // Signal 2
}
}
Backtest a strategy
- Use an external candlestick
- Use binance-vision
// Let's get some public data with the vision SpotClient
List<CandlestickBar> bars = new SpotClient()
.getKlines("BNBBTC", CandlestickInterval.FIVE_MINUTES, "2022", "01")
.getData();
//We instantiate the strategy
TwoPeriodRSIStrategy strategy = new TwoPeriodRSIStrategy();
//We run the backtest on the series
BackTestResult result = strategy.backTest(bars, CandlestickInterval.FIVE_MINUTES);
//We instantiate the strategy
TwoPeriodRSIStrategy strategy = new TwoPeriodRSIStrategy();
//Here we implicitly use binance4j-vision to download the data from binance servers
BackTestResult result = strategy.backTest("BNBBTC", CandlestickInterval.FIVE_MINUTES, "2022", "01");
Live trade
Live trading uses binance4j-websocket to get real-time klines data
TwoPeriodRSIStrategy strategy = new TwoPeriodRSIStrategy();
//The stream callback
StrategyCallback callback = new StrategyCallback();
//Stream is closed
callback.onClosed(websocketCloseObject -> {
//...
});
//Stream is closing
callback.onClosing(WebsocketCloseObject -> {
//...
});
//Stream is open
callback.onOpen(response -> {
//...
});
//connection failed/reading data failed/ping failed
callback.onFailure(apiException -> {
//...
});
//BUY signal (only called on final bar of interval)
callback.onEnter(series -> {
//...
});
//SELL signal (only called on final bar of interval)
callback.onExit(series-> {
//...
});
//every tick
callback.onMessage(symbolBar -> {
//...
});
// We set the inner BarSeries size. Default is 500.
strategy.setMaximumBarCount(200);
//We start live trading
WebsocketClient wsClient = strategy.watch("BNBBTC", CandlestickInterval.ONE_MINUTE, callback);
//We stop live trading
strategy.unwatch();
Watch multiple symbols
A strategy can watch multiple symbols at the same time. Just use a string with symbols separated by a coma:
WebsocketClient wsClient = strategy.watch("BNBBTC,BTCBUSD,SHIBBUSD", CandlestickInterval.ONE_MINUTE, callback);
or with a collection:
WebsocketClient wsClient = strategy.watch(List.of("BNBBTC","BTCBUSD","SHIBBUSD"), CandlestickInterval.ONE_MINUTE, callback);
The strategy will create a BarSeries
instance for every symbol.
To know the symbol of the series returned by onEnter
and onExit
, do as follow:
callback.onEnter(series -> {
series.getName(); // returns the symbol
});
callback.onExit(series-> {
series.getName(); // returns the symbol
});
To know the symbol of the bar returned by onMessage
, do as follow:
//every tick
callback.onMessage(symbolBar -> {
symbolBar.getSymbol(); // returns the symbol
});
Get strategy position over a candlestick
The strategy can also give its trading position over the bars.
// Let's get some public data with the vision SpotClient
List<CandlestickBar> bars = new SpotClient()
.getKlines("BNBBTC", CandlestickInterval.FIVE_MINUTES, "2022", "01")
.getData();
// We instantiate the strategy
TwoPeriodRSIStrategy strategy = new TwoPeriodRSIStrategy();
// Here we get the position of the strategy on the last bar of the series
boolean shouldEnter = strategy.shouldEnter(bars, CandlestickInterval.FIVE_MINUTES);
boolean shouldExit = strategy.shouldExit(bars, CandlestickInterval.FIVE_MINUTES);
// Here we get the position of the strategy on the 6th bar of the series
boolean shouldEnter = strategy.shouldEnter(bars, CandlestickInterval.FIVE_MINUTES, 5);
boolean shouldExit = strategy.shouldExit(bars, CandlestickInterval.FIVE_MINUTES, 5);
The CandlestickBar
list will be converted at every method call.
To prevent useless computation, you can convert the list into a BarSeries
before giving it to the methods.
// Let's get some public data with the vision SpotClient
List<CandlestickBar> bars = new SpotClient()
.getKlines("BNBBTC", CandlestickInterval.FIVE_MINUTES, "2022", "01")
.getData();
// We convert the bars into a BarSeries
BarSeries series = BarSeriesService.convert(bars, CandlestickInterval.FIVE_MINUTES);
//We instantiate the strategy
TwoPeriodRSIStrategy strategy = new TwoPeriodRSIStrategy();
// Here we get the position of the strategy on the last bar of the series
boolean shouldEnter = strategy.shouldEnter(series);
boolean shouldExit = strategy.shouldExit(series);
//Here we get the position of the strategy on the 6th bar of the series
boolean shouldEnter = strategy.shouldEnter(series, 5);
boolean shouldExit = strategy.shouldExit(series, 5);