Haehnchen / crypto-trading-bot

Cryptocurrency trading bot in javascript for Bitfinex, Bitmex, Binance, Bybit ... (public edition)
MIT License
3.1k stars 979 forks source link

Signal Ticker Interval #55

Open doftorul opened 5 years ago

doftorul commented 5 years ago

How does the bot actually use the Ticker Interval ? The backtest gives different results when the parameter "ticker_interval" is changed from its default forced 15 minutes but there is no way to apply a strategy with this setting changed.

In trade.js

setInterval(() => { eventEmitter.emit('signal_tick', {}) }, this.systemUtil.getConfig('tick.signal', 10600))

In conf.json "tick": { "default": null, "warmup": null, "signal": null, "watchdog": null, "ordering": null, "pair_signal_concurrency": null },

In http.js res.render('../templates/backtest_submit.html.twig', await this.backtest.getBacktestResult( parseInt(req.body['ticker_interval']), req.body.hours, req.body.strategy, req.body.candle_period, pair[0], pair[1], req.body.options ? JSON.parse(req.body.options) : {} ))

In backtest.js the parameter is used in GetBacktestResult

Haehnchen commented 5 years ago

this are different thinks.

"signal_tick" are just how often signals should be checked for trading, so eg every 10sec there is a check if a strategy was given a new signal or if a signal was finalized. i am using here the event system because of exchange overloading, there is a retry and the signal is fullfilled. (but will think about this idea to directly use the signal triggers). on other bots i had the issues that the "big signal" were not execute because of http errors.

the signal tick in backtesting is just used on how often the backtest should trigger the strategy and in how detail the result should be. so basically the idea is here if you work with 15m and with 1m candles, you can look in detail whats in the lower timeframe by using a 1 minute tick.

doftorul commented 5 years ago

Thank you for your fast response. It is still unclear which parameters need to be set in order to use 5m candles in a strategy and fire the signal checker every minute.

Haehnchen commented 5 years ago

the current candles are triggered against the strategy every 'tick.signal' ~10sec (10600ms). you can higher the value to match 60sec, then your strategy is trigger every minute.

in the strategy you can join what you need. eg 5m, 15m, 1m. maybe this example can help you:

'use strict';

let SignalResult = require('../dict/signal_result')
const SD = require('technicalindicators').SD
const SMA = require('technicalindicators').SMA
const TA = require('../../../utils/technical_analysis')
const TechnicalPattern = require('../../../utils/technical_pattern')
let resample = require('../../../utils/resample')
let TechnicalAnalysis = require('../../../utils/technical_analysis')
let Lowest = require('technicalindicators').Lowest;
let isTrendingUp = require('technicalindicators').isTrendingUp;
let isTrendingDown = require('technicalindicators').isTrendingDown;

module.exports = class {
    getName() {
        return 'trader'
    }

    buildIndicator(indicatorBuilder, options) {
        indicatorBuilder.add('candles_1m', 'candles', '1m')
        indicatorBuilder.add('bb', 'bb', '15m', {
            'length': 40,
        })
    }

    async period(indicatorPeriod, options) {
        let currentValues = indicatorPeriod.getLatestIndicators()

        let result = SignalResult.createEmptySignal(currentValues);

        let candles1m = indicatorPeriod.getIndicator('candles_1m')
        if(!candles1m) {
            return result
        }

        let candles3m = resample.resampleMinutes(candles1m.slice().reverse(), '3')

        let foo = TechnicalAnalysis.getPivotPoints(candles1m.slice(-10).map(c => c.close), 3, 3)

        let bb = indicatorPeriod.getLatestIndicator('bb')

        let lastCandle = candles1m.slice(-1)[0]
        result.addDebug('price2', lastCandle.close);

        if (bb && lastCandle && lastCandle.close > bb.upper) {
            result.addDebug('v', 'success');

            let bb = indicatorPeriod.getIndicator('bb')

            let values = bb.slice(-10).reverse().map(b => b.width);
            let value = Math.min(...values);

            if (currentValues.bb.width < 0.05) {
                result.addDebug('x', currentValues.bb.width);
                result.setSignal('long')
            }
        }

        result.addDebug('pivot', foo);

        result.mergeDebug(TechnicalPattern.volumePump(candles3m.slice().reverse() || []))

        return result
    }

    getBacktestColumns() {
        return [
            {
                'label': 'price2',
                'value': 'price2',
            },
            {
                'label': 'RSI',
                'value': 'rsi',
            },
            {
                'label': 'roc',
                'value': 'roc_1m',
            },
            {
                'label': 'roc_ma',
                'value': 'roc_ma',
                'type': 'icon',
            },
            {
                'label': 'Vol',
                'value': 'candles_1m.volume',
            },
            {
                'label': 'VolSd',
                'value': 'volume_sd',
            },
            {
                'label': 'VolV',
                'value': 'volume_v',
            },
            {
                'label': 'hint',
                'value': 'hint',
                'type': 'icon',
            },
            {
                'label': 'v',
                'value': 'v',
                'type': 'icon',
            },
            {
                'label': 'x',
                'value': 'x',
            },
            {
                'label': 'pivot',
                'value': 'pivot',
            },
        ]
    }

    getOptions() {
        return {
            'period': '15m',
        }
    }
}