Exemple #1
0
 def initiate(self, routes: list, extra_routes: list = None):
     if extra_routes is None:
         extra_routes = []
     self.set_routes(routes)
     self.set_extra_candles(extra_routes)
     from jesse.store import store
     store.reset(force_install_routes=jh.is_unit_testing())
Exemple #2
0
def set_up():
    reset_config()
    config['app']['trading_exchanges'] = [
        exchanges.SANDBOX, exchanges.BITFINEX
    ]
    config['app']['trading_symbols'] = ['BTCUSD', 'ETHUSD']
    store.reset()
Exemple #3
0
def test_backtesting_three_routes():
    reset_config()
    router.set_routes([
        (exchanges.SANDBOX, 'BTCUSD', timeframes.MINUTE_5, 'Test19'),
        (exchanges.SANDBOX, 'ETHUSD', timeframes.MINUTE_5, 'Test19'),
        (exchanges.SANDBOX, 'XRPUSD', timeframes.MINUTE_15, 'Test19'),
    ])
    store.reset(True)
    candles = {}
    routes = router.routes
    for r in routes:
        key = jh.key(r.exchange, r.symbol)
        candles[key] = {
            'exchange': r.exchange,
            'symbol': r.symbol,
            'candles': fake_range_candle(5 * 3 * 20)
        }

        # assert that strategy hasn't been initiated before running backtest_mode()
        assert r.strategy is None

    # run backtest (dates are fake just to pass)
    backtest_mode.run('2019-04-01', '2019-04-02', candles)

    # there must be three positions present with the updated current_price
    assert len(store.positions.storage) == 3

    for r in routes:
        # r3's '15m' timeframe makes r1 and r2 to support
        # '15' timeframe as well. r1 and r2 also make r3
        # to support '5m' timeframe also.
        r_one_min = store.candles.get_candles(r.exchange, r.symbol, '1m')
        r_five_min = store.candles.get_candles(r.exchange, r.symbol, '5m')
        r_fifteen_min = store.candles.get_candles(r.exchange, r.symbol, '15m')

        # assert the count of present candles
        assert len(r_one_min) == (5 * 3) * 20
        assert len(r_five_min) == 20 * 3
        assert len(r_fifteen_min) == 20

        r_first_1 = r_one_min[0]
        r_last_1 = r_one_min[-1]
        r_first_5 = r_five_min[0]
        r_last_5 = r_five_min[-1]
        r_first_15 = r_fifteen_min[0]
        r_last_15 = r_fifteen_min[-1]

        # assert timestamps
        assert r_first_1[0] == r_first_5[0]
        assert r_last_1[0] == (r_last_5[0] + 60000 * 4)
        assert r_last_5[0] == (r_last_15[0] + 60000 * 10)

        # assert positions
        p = selectors.get_position(r.exchange, r.symbol)
        assert p.is_close is True
        last_candle = store.candles.get_candles(r.exchange, r.symbol, '1m')[-1]
        assert p.current_price == last_candle[2]

        # assert that the strategy has been initiated
        assert r.strategy is not None
Exemple #4
0
def set_up(count=2):
    reset_config()
    config['app']['considering_timeframes'] = ['1m', '5m']
    config['app']['considering_symbols'] = ['BTCUSD']
    config['app']['considering_exchanges'] = ['Sandbox']
    store.reset()
    store.candles.init_storage(count)
Exemple #5
0
def set_up_with_fee(is_futures_trading=False):
    reset_config()
    config['env']['exchanges'][exchanges.SANDBOX]['fee'] = 0.002
    config['env']['exchanges'][exchanges.SANDBOX]['assets'] = [
        {
            'asset': 'USDT',
            'balance': 1000
        },
        {
            'asset': 'BTC',
            'balance': 0
        },
    ]
    if is_futures_trading:
        # used only in futures trading
        config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'futures'
    else:
        config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'spot'
    config['env']['exchanges'][
        exchanges.SANDBOX]['settlement_currency'] = 'USDT'
    config['app']['trading_mode'] = 'backtest'
    config['app']['considering_exchanges'] = ['Sandbox']
    router.set_routes([(exchanges.SANDBOX, 'BTC-USDT', '5m', 'Test19')])
    store.reset(True)

    global position
    global exchange
    global broker
    position = selectors.get_position(exchanges.SANDBOX, 'BTC-USDT')
    position.current_price = 50
    exchange = selectors.get_exchange(exchanges.SANDBOX)
    broker = Broker(position, exchanges.SANDBOX, 'BTC-USDT',
                    timeframes.MINUTE_5)
Exemple #6
0
def set_up():
    reset_config()
    config['app']['considering_exchanges'] = [exchanges.SANDBOX]
    config['app']['trading_exchanges'] = [exchanges.SANDBOX]
    config['app']['trading_symbols'] = ['BTC-USD']
    config['app']['trading_timeframes'] = ['5m']
    store.reset()
Exemple #7
0
def test_forming_candles():
    reset_config()
    router.set_routes([(exchanges.SANDBOX, 'BTC-USDT', timeframes.MINUTE_5,
                        'Test19')])
    router.set_extra_candles([(exchanges.SANDBOX, 'BTC-USDT',
                               timeframes.MINUTE_15)])
    store.reset(True)

    candles = {}
    key = jh.key(exchanges.SANDBOX, 'BTC-USDT')
    candles[key] = {
        'exchange': exchanges.SANDBOX,
        'symbol': 'BTC-USDT',
        'candles': test_candles_0
    }

    backtest_mode.run('2019-04-01', '2019-04-02', candles)

    # use math.ceil because it must include forming candle too
    assert len(
        store.candles.get_candles(exchanges.SANDBOX, 'BTC-USDT',
                                  timeframes.MINUTE_5)) == math.ceil(1382 / 5)
    assert len(
        store.candles.get_candles(exchanges.SANDBOX, 'BTC-USDT',
                                  timeframes.MINUTE_15)) == math.ceil(1382 /
                                                                      15)
Exemple #8
0
def set_up_without_fee(is_margin_trading=False):
    reset_config()
    config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'margin'
    config['env']['exchanges'][exchanges.SANDBOX]['fee'] = 0
    config['env']['exchanges'][exchanges.SANDBOX]['assets'] = [
        {
            'asset': 'USDT',
            'balance': 1000
        },
        {
            'asset': 'BTC',
            'balance': 0
        },
    ]
    if is_margin_trading:
        # used only in margin trading
        config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'margin'
        config['env']['exchanges'][
            exchanges.SANDBOX]['settlement_currency'] = 'USDT'
    config['app']['trading_mode'] = 'backtest'
    config['app']['considering_exchanges'] = ['Sandbox']
    router.set_routes([(exchanges.SANDBOX, 'BTC-USDT', '5m', 'Test19')])
    store.reset(True)

    global position
    global exchange
    position = selectors.get_position(exchanges.SANDBOX, 'BTC-USDT')
    position.current_price = 50
    exchange = selectors.get_exchange(exchanges.SANDBOX)
Exemple #9
0
def set_up(routes, fee=0):
    reset_config()
    config['env']['exchanges'][exchanges.SANDBOX]['starting_balance'] = 10000
    config['env']['exchanges'][exchanges.SANDBOX]['fee'] = fee
    router.set_routes(routes)
    router.set_extra_candles([])
    store.reset(True)
Exemple #10
0
def set_up(routes=None,
           is_futures_trading=True,
           leverage=1,
           leverage_mode='cross'):
    reset_config()
    config['env']['exchanges'][exchanges.SANDBOX]['assets'] = [
        {
            'asset': 'USDT',
            'balance': 10_000
        },
        {
            'asset': 'BTC',
            'balance': 0
        },
        {
            'asset': 'ETH',
            'balance': 0
        },
    ]

    if is_futures_trading:
        # used only in futures trading
        config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'futures'
        config['env']['exchanges'][
            exchanges.SANDBOX]['futures_leverage_mode'] = leverage_mode
        config['env']['exchanges'][
            exchanges.SANDBOX]['futures_leverage'] = leverage
    else:
        config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'spot'

    if routes:
        router.set_routes(routes)

    store.reset(True)
Exemple #11
0
def test_routes():
    # re-define routes
    router.set_routes([
        (exchanges.BITFINEX, 'ETHUSD', timeframes.HOUR_3, 'Test19'),
        (exchanges.SANDBOX, 'BTCUSD', timeframes.MINUTE_15, 'Test19'),
    ])

    router.set_extra_candles([
        (exchanges.BITFINEX, 'EOSUSD', timeframes.HOUR_3),
        (exchanges.BITFINEX, 'EOSUSD', timeframes.HOUR_1),
    ])

    # reset store for new routes to take affect
    store.reset(True)

    # now assert it's working as expected
    assert set(config['app']['trading_exchanges']) == set(
        [exchanges.SANDBOX, exchanges.BITFINEX])
    assert set(config['app']['trading_symbols']) == set(['BTCUSD', 'ETHUSD'])
    assert set(config['app']['trading_timeframes']) == set(
        [timeframes.HOUR_3, timeframes.MINUTE_15])
    assert set(config['app']['considering_exchanges']) == set(
        [exchanges.SANDBOX, exchanges.BITFINEX])
    assert set(config['app']['considering_symbols']) == set(
        ['BTCUSD', 'ETHUSD', 'EOSUSD'])
    assert set(config['app']['considering_timeframes']) == set([
        timeframes.MINUTE_1, timeframes.HOUR_3, timeframes.MINUTE_15,
        timeframes.HOUR_1
    ])
Exemple #12
0
def set_up():
    """

    """
    reset_config()
    config['app']['considering_candles'] = [('Sandbox', 'BTCUSD')]
    store.reset()
    store.trades.init_storage()
Exemple #13
0
def set_up(routes):
    """

    :param routes:
    """
    reset_config()
    router.set_routes(routes)
    store.reset(True)
Exemple #14
0
def set_up():
    reset_config()
    config['app']['considering_exchanges'] = [exchanges.SANDBOX]
    config['env']['exchanges'][exchanges.SANDBOX]['fee'] = 0
    config['env']['exchanges'][exchanges.SANDBOX]['starting_balance'] = 1000
    config['app']['trading_exchanges'] = [exchanges.SANDBOX]
    config['app']['trading_symbols'] = ['BTCUSD']
    config['app']['trading_timeframes'] = ['5m']
    store.reset()
def set_up(routes, is_margin_trading=True):
    reset_config()
    if is_margin_trading:
        # used only in margin trading
        config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'margin'
    else:
        config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'spot'
    router.set_routes(routes)
    store.reset(True)
Exemple #16
0
def test_backtesting_one_route():
    reset_config()
    router.set_routes([
        (exchanges.SANDBOX, 'BTC-USDT', timeframes.MINUTE_5, 'Test19')
    ])
    config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'margin'
    store.reset(True)

    candles = {}
    key = jh.key(exchanges.SANDBOX, 'BTC-USDT')
    candles[key] = {
        'exchange': exchanges.SANDBOX,
        'symbol': 'BTC-USDT',
        'candles': fake_range_candle(5 * 20)
    }
    routes = router.routes

    # assert that strategy hasn't been initiated before running backtest_mode()
    assert routes[0].strategy is None

    # run backtest (dates are fake just to pass)
    backtest_mode.run('2019-04-01', '2019-04-02', candles)

    one_min = store.candles.get_candles(exchanges.SANDBOX, 'BTC-USDT', '1m')
    five_min = store.candles.get_candles(exchanges.SANDBOX, 'BTC-USDT', '5m')

    # assert the count of present candles
    assert len(five_min) == 20
    assert len(one_min) == 20 * 5

    first_1 = one_min[0]
    last_1 = one_min[-1]
    first_5 = five_min[0]
    last_5 = five_min[-1]

    # assert time in store
    assert store.app.time == last_1[0] + 60000

    # assert timestamps
    assert first_1[0] == first_5[0]
    assert last_1[0] == (last_5[0] + 60000 * 4)

    # there must be only one positions present
    assert len(store.positions.storage) == 1
    p = selectors.get_position(exchanges.SANDBOX, 'BTC-USDT')
    assert p.is_close
    assert p.current_price == last_1[2]
    assert p.current_price == last_5[2]

    # assert routes
    assert len(routes) == 1
    assert routes[0].exchange == exchanges.SANDBOX
    assert routes[0].symbol == 'BTC-USDT'
    assert routes[0].timeframe == '5m'
    assert routes[0].strategy_name == 'Test19'
    # assert that the strategy has been initiated
    assert routes[0].strategy is not None
def set_up():
    reset_config()
    config['app']['considering_exchanges'] = [exchanges.SANDBOX]
    config['app']['trading_exchanges'] = [exchanges.SANDBOX]
    config['env']['exchanges'][exchanges.SANDBOX]['assets'] = [{
        'asset': 'USDT',
        'balance': 2000
    }]
    store.reset()
Exemple #18
0
def set_up():
    """

    """
    reset_config()
    config['app']['considering_exchanges'] = [exchanges.SANDBOX]
    config['app']['trading_exchanges'] = [exchanges.SANDBOX]
    config['env']['exchanges'][exchanges.SANDBOX]['starting_balance'] = 2000
    store.reset()
Exemple #19
0
def test_must_not_be_able_to_set_two_similar_routes():
    reset_config()
    router.set_routes([
        (exchanges.SANDBOX, 'ETH-USDT', timeframes.MINUTE_5, 'Test01'),
        (exchanges.SANDBOX, 'ETH-USDT', timeframes.MINUTE_30, 'Test02'),
    ])
    with pytest.raises(Exception) as err:
        store.reset(True)
    assert str(err.value).startswith(
        'each exchange-symbol pair can be traded only once')
Exemple #20
0
def set_up(routes, fee=0):
    reset_config()
    config['env']['exchanges'][exchanges.SANDBOX]['assets'] = [
        {'asset': 'USDT', 'balance': 1000},
        {'asset': 'BTC', 'balance': 0},
    ]
    config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'margin'
    config['env']['exchanges'][exchanges.SANDBOX]['fee'] = fee
    router.set_routes(routes)
    router.set_extra_candles([])
    store.reset(True)
Exemple #21
0
def set_up(routes, is_margin_trading=True):
    reset_config()
    config['env']['exchanges'][exchanges.SANDBOX]['assets'] = [
        {'asset': 'USDT', 'balance': 10000},
        {'asset': 'BTC', 'balance': 0},
        {'asset': 'ETH', 'balance': 0},
    ]
    if is_margin_trading:
        # used only in margin trading
        config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'margin'
    else:
        config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'spot'
    router.set_routes(routes)
    store.reset(True)
Exemple #22
0
def set_up_with_fee():
    reset_config()
    config['env']['exchanges'][exchanges.SANDBOX]['fee'] = 0.002
    config['env']['exchanges'][exchanges.SANDBOX]['starting_balance'] = 1000
    config['app']['trading_mode'] = 'backtest'
    config['app']['considering_exchanges'] = ['Sandbox']
    router.set_routes([(exchanges.SANDBOX, 'BTCUSD', '5m', 'Test19')])
    store.reset(True)

    global position
    global exchange
    global broker
    position = selectors.get_position(exchanges.SANDBOX, 'BTCUSD')
    position.current_price = 50
    exchange = selectors.get_exchange(exchanges.SANDBOX)
    broker = Broker(position, exchanges.SANDBOX, 'BTCUSD', timeframes.MINUTE_5)
Exemple #23
0
def test_routes():
    # re-define routes
    router.set_routes([
        {
            'exchange': exchanges.BITFINEX,
            'symbol': 'ETH-USD',
            'timeframe': timeframes.HOUR_3,
            'strategy': 'Test19'
        },
        {
            'exchange': exchanges.SANDBOX,
            'symbol': 'BTC-USD',
            'timeframe': timeframes.MINUTE_15,
            'strategy': 'Test19'
        },
    ])

    router.set_extra_candles([
        {
            'exchange': exchanges.BITFINEX,
            'symbol': 'EOS-USD',
            'timeframe': timeframes.HOUR_3
        },
        {
            'exchange': exchanges.BITFINEX,
            'symbol': 'EOS-USD',
            'timeframe': timeframes.HOUR_1
        },
    ])

    # reset store for new routes to take affect
    store.reset(True)

    # now assert it's working as expected
    assert set(config['app']['trading_exchanges']) == set(
        [exchanges.SANDBOX, exchanges.BITFINEX])
    assert set(config['app']['trading_symbols']) == set(['BTC-USD', 'ETH-USD'])
    assert set(config['app']['trading_timeframes']) == set(
        [timeframes.HOUR_3, timeframes.MINUTE_15])
    assert set(config['app']['considering_exchanges']) == set(
        [exchanges.SANDBOX, exchanges.BITFINEX])
    assert set(config['app']['considering_symbols']) == set(
        ['BTC-USD', 'ETH-USD', 'EOS-USD'])
    assert set(config['app']['considering_timeframes']) == set([
        timeframes.MINUTE_1, timeframes.HOUR_3, timeframes.MINUTE_15,
        timeframes.HOUR_1
    ])
Exemple #24
0
def set_up():
    reset_config()
    from jesse.routes import router
    router.set_routes([{
        'exchange': 'Sandbox',
        'symbol': 'BTC-USD',
        'timeframe': '1m',
        'strategy': 'Test01'
    }])
    router.set_extra_candles([{
        'exchange': 'Sandbox',
        'symbol': 'BTC-USD',
        'timeframe': '5m'
    }])
    config['app']['considering_timeframes'] = ['1m', '5m']
    config['app']['considering_symbols'] = ['BTC-USD']
    config['app']['considering_exchanges'] = ['Sandbox']
    store.reset(True)
    store.candles.init_storage()
def test_can_add_trade_to_store():
    set_up()

    assert store.completed_trades.trades == []

    trade = CompletedTrade({
        'type': 'long',
        'exchange': 'Sandbox',
        'entry_price': 10,
        'exit_price': 20,
        'take_profit_at': 20,
        'stop_loss_at': 5,
        'qty': 1,
        'orders': [],
        'symbol': 'BTC-USD',
        'opened_at': 1552309186171,
        'closed_at': 1552309186171 + 60000
    })

    store.completed_trades.add_trade(trade)
    assert store.completed_trades.trades == [trade]
    store.reset()
    assert store.completed_trades.trades == []
Exemple #26
0
    def fitness(self, dna) -> tuple:
        hp = jh.dna_to_hp(self.strategy_hp, dna)

        # init candle store
        store.candles.init_storage(5000)
        # inject required TRAINING candles to the candle store

        for num, c in enumerate(config['app']['considering_candles']):
            required_candles.inject_required_candles_to_store(
                self.training_initial_candles[num], c[0], c[1])

        # run backtest simulation
        simulator(self.training_candles, hp)

        log = ''

        # TODO: some of these have to be dynamic based on how many days it's trading for like for example "total"
        # I'm guessing we should accept "optimal" total from command line
        if store.completed_trades.count > 5:
            training_data = stats.trades(store.completed_trades.trades,
                                         store.app.daily_balance)
            total_effect_rate = log10(training_data['total']) / log10(
                self.optimal_total)
            if total_effect_rate > 1:
                total_effect_rate = 1
            win_rate = training_data['win_rate']

            ratio_config = jh.get_config('env.optimization.ratio', 'sharpe')
            if ratio_config == 'sharpe':
                ratio = training_data['sharpe_ratio']
            elif ratio_config == 'calmar':
                ratio = training_data['calmar_ratio']
            elif ratio_config == 'sortiono':
                ratio = training_data['sortino_ratio']
            elif ratio_config == 'omega':
                ratio = training_data['omega_ratio']
            else:
                raise ValueError(
                    'The entered ratio configuration `{}` for the optimization is unknown. Choose between sharpe, calmar, sortino and omega.'
                    .format(ratio_config))

            if ratio < 0:
                score = 0.0001
                # reset store
                store.reset()
                return score, log

            ratio_normalized = jh.normalize(ratio, -.5, 4)

            # log for debugging/monitoring
            log = 'win-rate: {}%, total: {}, PNL: {}%'.format(
                int(win_rate * 100),
                training_data['total'],
                round(training_data['net_profit_percentage'], 2),
            )

            score = total_effect_rate * ratio_normalized

            # perform backtest with testing data. this is using data
            # model hasn't trained for. if it works well, there is
            # high change it will do good with future data too.
            store.reset()
            store.candles.init_storage(5000)
            # inject required TESTING candles to the candle store

            for num, c in enumerate(config['app']['considering_candles']):
                required_candles.inject_required_candles_to_store(
                    self.testing_initial_candles[num], c[0], c[1])

            # run backtest simulation
            simulator(self.testing_candles, hp)
            testing_data = stats.trades(store.completed_trades.trades,
                                        store.app.daily_balance)

            # log for debugging/monitoring
            log += ' || '
            if store.completed_trades.count > 0:
                log += 'win-rate: {}%, total: {}, PNL: {}%'.format(
                    int(testing_data['win_rate'] * 100),
                    testing_data['total'],
                    round(testing_data['net_profit_percentage'], 2),
                )
                if testing_data['net_profit_percentage'] > 0 and training_data[
                        'net_profit_percentage'] > 0:
                    log = jh.style(log, 'bold')
            else:
                log += 'win-rate: -, total: -, PNL%: -'
        else:
            score = 0.0001

        # reset store
        store.reset()

        return score, log
Exemple #27
0
    def fitness(self, dna) -> tuple:
        hp = jh.dna_to_hp(self.strategy_hp, dna)

        # init candle store
        store.candles.init_storage(5000)
        # inject required TRAINING candles to the candle store
        required_candles.inject_required_candles_to_store(
            self.required_initial_training_candles, self.exchange, self.symbol)
        # run backtest simulation
        simulator(self.training_candles, hp)

        log = ''

        # TODO: some of these have to be dynamic based on how many days it's trading for like for example "total"
        # I'm guessing we should accept "optimal" total from command line
        if store.completed_trades.count > 5:
            training_data = stats.trades(store.completed_trades.trades)
            optimal_expected_total = 100
            total = jh.normalize(training_data['total'], 0, 200)
            total_effect_rate = log10(
                training_data['total']) / log10(optimal_expected_total)
            win_rate = training_data['win_rate']

            # log for debugging/monitoring
            log = 'win_rate:[{}-{}], total:[{}-{}], PNL%:[{}], TER:[{}]'.format(
                round(win_rate, 2), round(training_data['win_rate'], 2),
                round(total, 2), training_data['total'],
                round(training_data['pnl_percentage'], 2),
                round(total_effect_rate, 3))

            # the fitness score
            score = win_rate * total_effect_rate

            # perform backtest with testing data. this is using data
            # model hasn't trained for. if it works well, there is
            # high change it will do good with future data too.
            store.reset()
            store.candles.init_storage(5000)
            # inject required TESTING candles to the candle store
            required_candles.inject_required_candles_to_store(
                self.required_initial_testing_candles, self.exchange,
                self.symbol)
            # run backtest simulation
            simulator(self.testing_candles, hp)
            testing_data = stats.trades(store.completed_trades.trades)

            # log for debugging/monitoring
            log += ' | '
            log += 'win_rate:[{}], total:[{}], PNL%:[{}]'.format(
                round(testing_data['win_rate'], 2),
                testing_data['total'],
                round(testing_data['pnl_percentage'], 2),
            )
            if testing_data['pnl_percentage'] > 0 and training_data[
                    'pnl_percentage'] > 0:
                log = jh.style(log, 'bold')
        else:
            score = 0.0001

        # reset store
        store.reset()

        return score, log
Exemple #28
0
def set_up(routes):
    reset_config()
    router.set_routes(routes)
    store.reset(True)
Exemple #29
0
def set_up():
    reset_config()
    config['app']['considering_candles'] = [('Sandbox', 'BTC-USD')]
    store.reset()
    store.tickers.init_storage()
Exemple #30
0
def set_up():
    """

    """
    reset_config()
    store.reset(True)