Custom strategies
Build completely custom trading strategies, using JavaScript. For spot and futures trading.
Use built-in trading methods, candle and indicator data to get started quickly.
For advanced usage it's possible to install and use your own additional javascript modules.
A strategy runs as an async function, executed once every time a trading pair 'cycles' in Gunbot.
note
Custom strategies are available in Gunbot Ultimate.
#
Technical infoTo get a better idea of what you can and can't do, here's a few facts:
- Gunbot takes care of the exchange connection, collecting data and making it available to a strategy
- You save strategies in your own .js files in a folder called ./customStrategies
- There is no Gunbot specific syntax, strategy code is plain JavaScript
- Strategy code has access to a single outside object:
gb
, which contains a number of trading methods and lots of data to work with - There are basically no restrictions to what you can do with the provided trading methods, but of course exchange defined restrictions apply (API usage rate limits, open orders limits, etc.)
- There are no protections against double orders, or any kind of other unwanted behavior
- Make sure to use JavaScript code compatible with Node v14.4.0
- Using
console.log()
logs to the main Gunbot console logs. Expect to console log all the things - Code runs inside an async function, you can use the
await
keyword to collect additional data like candle data for a different period - A strategy does not have to return anything, but you can use return statements to easily stop your code at a certain point
- A strategy can use custom JavaScript modules. Save these in a folder named
user_modules
inside your Gunbot folder.
danger
Custom code can be very risky!
Because external modules can be used, be extremely careful when running strategy code you did not write yourself. In theory a malicious actor can gain access over your whole system.
#
Strategy examplesCoding a strategy can be as difficult as you want it to be.
Even with very basic JavaScript code it's possible to create complex strategies.
The following examples show a few possible ways to code simple strategies. They are silly in functionality, and are not usable for actual trading. Each next example requires a bit more JavaScript knowledge.
danger
Some examples can lead to immediate large trades. Use them to learn, not to trade.
#
Example 1- Trade USDT-BTC
- Invest 100 USDT per trade, allow max 1 buy order
- Market buy when price is below lowBB and fastSma is below ema1 (using readily available indicator data)
- After the buy order fills, place a sell order 1% above the break even price
- Do nothing until this sell order fills
#
Example 2- Keep the basic workings from example 1
- Additionally calculate a Hull Moving Average (HMA) using the last 50 candle close prices as input
- Place the sell order 1% above bid price, at the moment bid goes above HMA
#
Example 3- Trade USDT-BTC
- Invest 100 USDT per trade, allow max 1 buy order
- Code a bit more readable, assigning variables for everything used in conditionals
- Buy when a 50 period ema has crossed over a 200 period ema, AND within at most 2 candles later the candle open price is above ema1
- Place a sell order 5% above break even
#
Example 4- Trade USDT-BTC and USDT-XRP
- Assume you already have BTC and XRP
- Sell 1 BTC when news about BTC tagged "bearish" appears on cryptopanic.com, containing the keyword "Korea", then place a buy order 5% below the current price
- Sell 10000 XRP whenever news about XRP tagged "bearish" appears with the keyword "sec"
- Do all of this in a single strategy running on a single pair in Gunbot
#
Example 5- Trade USDT-BTC
- Invest 100 USDT per trade, allow max 1 buy order
- Strategy itself uses 3m candles, additionally fetch 60m candles
- Only collect data and allow trades in first minute of the hour
- Calculate TD Sequential using an external module, transform input data to the needed format
- Place buy order when bid price > ema1, using 3m data AND TD Sequential on hourly chart has a buy setup index of 8 or higher
- Sell when TD sequential has a sell setup index of at least 11 and price is above break even
- Use the lodash module to simplify some code
#
"Real" strategy examplesThe following examples are more or less ready made strategies you can build upon.
Note that every custom strategy will require testing on your side. Do not blindly use these examples.
One aspect that's absent in the examples is checking if referenced data is actually defined before firing orders, in some cases this will be an important aspect of a custom strategy. Also consider adding error handling to your code, especially for trading methods that have less chance to succeed than simple market orders.
#
Keltner crossover#
Dual RSI#
Trail price after stochRsi target#
How to create and run a custom strategyTo create a new custom strategy, use custom as buy and sell method:
Then specify the filename with your strategy logic and place that file with your strategy logic in the ./customStrategies folder, inside the bot root folder.
The data tab gives you control over how pre calculated indicator data is generated. These are indicators you can access in your strategy. You are not limited to using these indicators, this is just easily accessible data.
To run the strategy, simply assign it to a trading pair like you would with any other Gunbot strategy.
tip
It's recommended to disable the global cancel orders option when running a custom strategy.
#
Trading methodsA strategy can use a number of methods to place or cancel orders, or fetch additional OHLCV data.
Trading methods can be called as function, without waiting for it's return value.
Alternatively, when calling a method you can wait for its Promise to resolve. This way you can create a promise chain using the then() method.
#
Built in modulesThe require module allow you to use additional javascript modules, like those freely available on NPM.
With tulind you can easily calculate your own indicator values.
Method | Returns | Extra info |
---|---|---|
gb.method.buyMarket(amount, pair) | Promise | Places a market buy order, amount in quote |
gb.method.sellMarket(amount, pair) | Promise | Places a market sell order, amount in quote |
gb.method.buyLimit(amount, price, pair) | Promise | Places a limit buy order, amount in quote |
gb.method.sellLimit(amount, price, pair) | Promise | Places a limit sell order, amount in quote |
gb.method.closeMarket(pair, amount) | Promise | Places a market close order, for futures. Amount in quote. |
gb.method.closeLimit(price, pair, amount) | Promise | Places a limit close order, for futures. Amount in quote. |
gb.method.cancelOrder(orderId, pair) | Promise | Cancels a specified open order. |
gb.method.getCandles(interval, period, pair) | Promise | Get additional OHLCV data. Easiest to call using Beware: frequent usage can quickly lead to exceeding exchange API rate limits. |
gb.method.getTrend(pair, exchange) | Promise | Returns an object with the same trend data as used in stepgridhybrid/stepgridhedge. Can only be called for pairs actively cycling. Calling this method leads to significant additional API usage, because candle data in 15m, 1h and 4h timeframes gets requested. Trend and candle data additionally gets stored to Gunbot pair state. |
gb.method.setTimeScaleMark(pair, exchange, message) | Mark on chart | Timescale marks are the marks on the chart x axis, that by default show details for filled orders. With this method you can display any string in a mark on a specific bar. When multiple messages get stored for the same candle, they will be shown together in one mark. Timestamp is set automatically, no need to include it in the message text. |
gb.method.tulind [#parameters#] | array | Get 100+ different indicators. You can use the available OHLCV data, or use your own inputs. See the example strategies for a usage example. |
gunbot.method.require(module) | function | Bring your own modules using require. See the example strategies for a usage example. To use an external module, first place it in a folder called 'user_modules' in the Gunbot root folder. Then require it in your strategy code, like this: On Linux (and likely macOS): On Windows: The above assumes you have a module in a folder called cryptopanic in the user_modules folder. |
#
Available dataA strategy can use all available pair data in Gunbot, easily accessible with unique property names.
Indicators mentioned in the list below are pre calculated using the indicator settings in your Gunbot strategy. Some indicators don't have configurable strategy parameters and just use the generally accepted standard inputs for the indicator.
Property | Returns | Extra info |
---|---|---|
gb.data.config | object | Gunbot config.js contents |
gb.data.pairLedger | object | Contains the complete pair ledger. Can also be used to store and access your own persistent variables. Make sure to not overwrite existing properties. This has the same data as you see in the pair JSON files. Most items below come from the ledger too, they are renamed for consistency and already parsed as floating point numbers. |
gb.data.pairName | string | Current pair name, like USDT-BTC |
gb.data.exchangeName | string | Current exchange name, like binance |
gb.data.balances | object | Object with all balances on same exchange |
gb.data.quoteBalance | float | Pair quote balance, like BTC balance on an USDT-BTC pair Specific to spot trading |
gb.data.baseBalance | float | Base balance, like USDT balance on an USDT-BTC pair |
gb.data.onOrdersBalance | float | Quote balance value of open orders for current pair |
gb.data.openOrders | array | Open orders for current pair |
gb.data.orders | array | History of filled orders for current pair |
gb.data.orderbook | object | First 10 bid and ask entries in orderbook, price and volume |
gb.data.breakEven | float | Break even price for current spot holdings. Includes trading fees as defined in Gunbot exchange settings |
gb.data.gotBag | boolean | Indicates if value of quoteBalance for spot trading (including on orders volume) exceeds min volume to sell as defined in Gunbot strategy |
gb.data.leverage | float | Leverage of current futures position |
gb.data.walletBalance | float | Wallet balance. Specific to futures |
gb.data.availableMargin | float | Available margin balance. Specific to futures |
gb.data.maintenanceMargin | float | Maintenance margin requirement for futures account |
gb.data.maxNotionalValue | float | Max notional value for futures position at current leverage |
gb.data.totalPositionInitialMargin | float | Total initial position margin requirement for all current futures positions |
gb.data.totalOpenOrderInitialMargin | float | Total initial margin requirement for open futures orders |
gb.data.currentQty | float | Futures position size |
gb.data.currentSide | string | Indicates current futures position side |
gb.data.liquidationPrice | float | Futures position liquidation price |
gb.data.period | float | Candle size as set in Gunbot strategy PERIOD setting. This period is used for all pre calculated indicator values |
gb.data.bid | float | Highest bid price |
gb.data.ask | float | Lowest ask price |
gb.data.ema1 | float | Latest indicator value |
gb.data.ema2 | float | Latest indicator value |
gb.data.ema3 | float | Latest indicator value |
gb.data.BTCUSDprice | float | Latest BTC/USD price on same exchange (or equivalent spot pair, depending on availability) |
gb.data.mfi | float | Latest indicator value |
gb.data.rsi | float | Latest indicator value |
gb.data.lowBB | float | Latest indicator value |
gb.data.highBB | float | Latest indicator value |
gb.data.tenkan | float | Latest indicator value |
gb.data.chikou | float | Latest indicator value |
gb.data.kijun | float | Latest indicator value |
gb.data.senkouSpanA | float | Latest indicator value |
gb.data.senkouSpanB | float | Latest indicator value |
gb.data.fastSma | float | Latest indicator value |
gb.data.slowSma | float | Latest indicator value |
gb.data.R1 | float | Latest indicator value |
gb.data.S1 | float | Latest indicator value |
gb.data.R2 | float | Latest indicator value |
gb.data.S2 | float | Latest indicator value |
gb.data.macd | float | Latest indicator value |
gb.data.macdSignal | float | Latest indicator value |
gb.data.macdHistogram | float | Latest indicator value |
gb.data.stochK | float | Latest indicator value |
gb.data.stochD | float | Latest indicator value |
gb.data.stochRsi | float | Latest indicator value |
gb.data.atr | float | Latest indicator value |
gb.data.fib | object | Object with high and low Fibonacci retracement levels |
gb.data.vwma | float | Latest indicator value |
gb.data.diPlus | float | Latest indicator value |
gb.data.diMinus | float | Latest indicator value |
gb.data.adx | float | Latest indicator value |
gb.data.candlesOpen | array | Array of open values for OHLCV Sorted old to new (newest last) |
gb.data.candlesHigh | array | Array of high values for OHLCV Sorted old to new (newest last) |
gb.data.candlesLow | array | Array of low values for OHLCV Sorted old to new (newest last) |
gb.data.candlesClose | array | Array of close values for OHLCV Sorted old to new (newest last) |
gb.data.candlesVolume | array | Array of volume values for OHLCV Sorted old to new (newest last) |
gb.data.candlesTimestamp | array | Array of timestamp values for OHLCV Sorted old to new (newest last) |
gb.data.candles | object | Combined object with OHLCV data |
#
Storing dataThe strategy code runs once every time Gunbot processes the pair. This means that any variable you assign inside the strategy gets reinitialized every time the code runs.
To store variables in a more persistent way, use this object:
gb.data.pairLedger.customStratStore
By default customStratStore
is undefined, you need to create it before storing anything in there.
Data saved here generally stays available, and persists between bot restarts. However, there is no guarantee the data stays intact - if for example the process gets killed it is possible the pair ledger gets reinitialized on next run. Gunbot native strategies are coded so that they depend as little as possible on internal persistently stored data, working with exchange provided data as much as possible. Consider doing the same when coding custom strategies.
#
Visualize strategy targetsTo easily monitor a custom strategy, trading targets can be visualized as lines on the chart in the GUI.
#
Simplest method to draw chart linesIf you set any of the following targets to a price, it's automatically drawn on the chart.
#
Complete control over chart linesAlternative to the 'easy' method, chart lines can be defined in pair ledger as an array of objects with more properties than just price. The number of lines and/or line properties can be changed at any time, the chart will reflect the changes within seconds
The following list of names cannot be used as text property for chart lines because they would conflict with existing charting options in non-custom Gunbot strategies:
#
Send notifications to the GUITo make the GUI display custom notifications, place one or more notifications in an array of objects in pair ledger. Once shown, the GUI automatically clears out the displayed notifications in pair ledger.
#
Add your own logsUse the node fs module to get access to the file system. The example code below can be used as a simple pattern to create your own log files.
#
Write config changesIt can be convenient for a strategy to change settings in the gunbot config file. After a change to this file, Gunbot picks up the changes automatically.
The following example can be used as a simple way to modify config.js
.
#
Control strategy parameters from the GUIJust like with every other strategy in Gunbot you can use pair overrides to control individual parameters of a strategy for a specific pair. This example shows how you can refer to an override value:
The whatstrat object is a merged object of all parameters in a Gunbot strategy and pair overrides, where pair overrides always take precedence over strategy values. Always make sure to parseFloat()
inputs where you expect a number, because the GUI saves these as string value.
Parameters saved as pair override do not have to be known parameters in Gunbot, you can create your own settings this way.