Exemple #1
0
def _simulate_price_change_effect(real_candle: np.ndarray, exchange: str,
                                  symbol: str) -> None:
    orders = store.orders.get_orders(exchange, symbol)

    current_temp_candle = real_candle.copy()
    executed_order = False

    while True:
        if len(orders) == 0:
            executed_order = False
        else:
            for index, order in enumerate(orders):
                if index == len(orders) - 1 and not order.is_active:
                    executed_order = False

                if not order.is_active:
                    continue

                if candle_includes_price(current_temp_candle, order.price):
                    storable_temp_candle, current_temp_candle = split_candle(
                        current_temp_candle, order.price)
                    store.candles.add_candle(storable_temp_candle,
                                             exchange,
                                             symbol,
                                             '1m',
                                             with_execution=False,
                                             with_generation=False)
                    p = selectors.get_position(exchange, symbol)
                    p.current_price = storable_temp_candle[2]

                    executed_order = True

                    order.execute()

                    # break from the for loop, we'll try again inside the while
                    # loop with the new current_temp_candle
                    break
                else:
                    executed_order = False

        if not executed_order:
            # add/update the real_candle to the store so we can move on
            store.candles.add_candle(real_candle,
                                     exchange,
                                     symbol,
                                     '1m',
                                     with_execution=False,
                                     with_generation=False)
            p = selectors.get_position(exchange, symbol)
            if p:
                p.current_price = real_candle[2]
            break

    _check_for_liquidations(real_candle, exchange, symbol)
Exemple #2
0
    def execute(self, silent=False) -> None:
        if self.is_canceled or self.is_executed:
            return

        self.executed_at = jh.now_to_timestamp()
        self.status = order_statuses.EXECUTED

        if jh.is_live():
            self.save()

        if not silent:
            txt = f'EXECUTED order: {self.symbol}, {self.type}, {self.side}, {self.qty}'
            if self.price:
                txt += f', ${round(self.price, 2)}'
            # log
            if jh.is_debuggable('order_execution'):
                logger.info(txt)
            # notify
            if jh.is_live():
                self.broadcast()
                if config['env']['notifications']['events']['executed_orders']:
                    notify(txt)

        p = selectors.get_position(self.exchange, self.symbol)

        if p:
            p._on_executed_order(self)

        # handle exchange balance for ordered asset
        e = selectors.get_exchange(self.exchange)
        e.on_order_execution(self)
Exemple #3
0
    def available_margin(self, symbol: str = '') -> float:
        # a temp which gets added to per each asset (remember that all future assets use the same currency for settlement)
        temp_credits = self.assets[self.settlement_currency]

        # we need to consider buy and sell orders of ALL pairs
        # also, consider the value of all open positions
        for asset in self.assets:
            if asset == self.settlement_currency:
                continue

            position = selectors.get_position(self.name, f"{asset}-{self.settlement_currency}")
            if position is None:
                continue

            if position.is_open:
                # add unrealized PNL
                temp_credits += position.pnl

            # only which of these has actual values, so we can count all of them!
            sum_buy_orders = (self.buy_orders[asset][:][:, 0] * self.buy_orders[asset][:][:, 1]).sum()
            sum_sell_orders = (self.sell_orders[asset][:][:, 0] * self.sell_orders[asset][:][:, 1]).sum()

            if position.is_open:
                temp_credits -= position.total_cost

            # Subtract the amount we paid for open orders. Notice that this does NOT include
            # reduce_only orders so either sum_buy_orders or sum_sell_orders is zero. We also
            # care about the cost we actually paid for it which takes into account the leverage
            temp_credits -= max(
                abs(sum_buy_orders) / self.futures_leverage, abs(sum_sell_orders) / self.futures_leverage
            )

        # count in the leverage
        return temp_credits * self.futures_leverage
Exemple #4
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 #5
0
    def cancel(self):
        """

        :return:
        """
        if self.is_canceled or self.is_executed:
            return

        self.canceled_at = jh.now()
        self.status = order_statuses.CANCELED

        if jh.is_debuggable('order_cancellation'):
            logger.info(
                'CANCELED order: {}, {}, {}, {}, ${}'.format(
                    self.symbol, self.type, self.side, self.qty, round(self.price, 2)
                )
            )

        # notify
        if jh.is_live() and config['env']['notifications']['events']['cancelled_orders']:
            notify(
                'CANCELED order: {}, {}, {}, {}, {}'.format(
                    self.symbol, self.type, self.side, self.qty, round(self.price, 2)
                )
            )

        p = selectors.get_position(self.exchange, self.symbol)
        if p:
            p._on_canceled_order(self)
Exemple #6
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 #7
0
def _check_for_liquidations(candle: np.ndarray, exchange: str, symbol: str) -> None:
    p: Position = selectors.get_position(exchange, symbol)

    if not p:
        return

    # for now, we only support the isolated mode:
    if p.mode != 'isolated':
        return

    if candle_includes_price(candle, p.liquidation_price):
        closing_order_side = jh.closing_side(p.type)

        # create the market order that is used as the liquidation order
        order = Order({
            'id': jh.generate_unique_id(),
            'symbol': symbol,
            'exchange': exchange,
            'side': closing_order_side,
            'type': order_types.MARKET,
            'flag': order_flags.REDUCE_ONLY,
            'qty': jh.prepare_qty(p.qty, closing_order_side),
            'price': p.bankruptcy_price,
            'role': order_roles.CLOSE_POSITION
        })

        store.orders.add_order(order)

        store.app.total_liquidations += 1

        logger.info(f'{p.symbol} liquidated at {p.liquidation_price}')

        order.execute()
Exemple #8
0
    def execute(self):
        if self.is_canceled or self.is_executed:
            return

        self.executed_at = jh.now_to_timestamp()
        self.status = order_statuses.EXECUTED

        # log
        if jh.is_debuggable('order_execution'):
            logger.info('EXECUTED order: {}, {}, {}, {}, ${}'.format(
                self.symbol, self.type, self.side, self.qty,
                round(self.price, 2)))
        # notify
        if jh.is_live(
        ) and config['env']['notifications']['events']['executed_orders']:
            notify('EXECUTED order: {}, {}, {}, {}, {}'.format(
                self.symbol, self.type, self.side, self.qty,
                round(self.price, 2)))

        p = selectors.get_position(self.exchange, self.symbol)

        if p:
            p._on_executed_order(self)

        # handle exchange balance for ordered asset
        e = selectors.get_exchange(self.exchange)
        e.on_order_execution(self)
Exemple #9
0
    def available_margin(self, symbol: str = '') -> float:
        temp_credit = self.assets[self.settlement_currency] * self.futures_leverage
        # we need to consider buy and sell orders of ALL pairs
        # also, consider the value of all open positions
        for asset in self.assets:
            if asset == self.settlement_currency:
                continue

            position = selectors.get_position(self.name, asset + "-" + self.settlement_currency)
            if position is None:
                continue

            if position.is_open:
                # add unrealized PNL
                temp_credit += position.pnl

            # subtract worst scenario orders' used margin
            sum_buy_orders = (self.buy_orders[asset][:][:, 0] * self.buy_orders[asset][:][:, 1]).sum()
            sum_sell_orders = (self.sell_orders[asset][:][:, 0] * self.sell_orders[asset][:][:, 1]).sum()
            if position.is_open:
                if position.type == 'long':
                    sum_buy_orders += position.value
                else:
                    sum_sell_orders -= abs(position.value)
            temp_credit -= max(abs(sum_buy_orders), abs(sum_sell_orders))

        return temp_credit
Exemple #10
0
def test_strategy_properties():
    set_up([
        (exchanges.SANDBOX, 'ETHUSDT', timeframes.MINUTE_5, 'Test19'),
        (exchanges.SANDBOX, 'BTCUSDT', timeframes.MINUTE_5, 'Test19'),
    ])

    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)
        }

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

    for r in routes:
        s: Strategy = r.strategy

        assert s.name == r.strategy_name
        assert s.symbol == r.symbol
        assert s.exchange == r.exchange
        assert s.timeframe == r.timeframe
        assert s.trade is None
        assert s._is_executing is False
        assert s._is_initiated is True
        np.testing.assert_equal(s.current_candle, store.candles.get_current_candle(r.exchange, r.symbol, r.timeframe))
        np.testing.assert_equal(s.candles, store.candles.get_candles(r.exchange, r.symbol, r.timeframe))
        assert s.position == selectors.get_position(r.exchange, r.symbol)
        assert s.orders == store.orders.get_orders(r.exchange, r.symbol)
Exemple #11
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 #12
0
 def _init_objects(self):
     """
     This method gets called after right creating the Strategy object. It
     is just a workaround as a part of not being able to set them inside
     self.__init__() for the purpose of removing __init__() methods from strategies.
     """
     self.position = selectors.get_position(self.exchange, self.symbol)
     self.broker = Broker(self.position, self.exchange, self.symbol, self.timeframe)
Exemple #13
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
Exemple #14
0
    def update_position(exchange: str, symbol: str, candle: np.ndarray):
        # get position object
        p = selectors.get_position(exchange, symbol)

        # for extra_route candles, p == None, hence no further action is required
        if p is None:
            return

        # update position.current_price
        p.current_price = jh.round_price_for_live_mode(candle[2], candle[2])
Exemple #15
0
    def _init_objects(self) -> None:
        """
        This method gets called after right creating the Strategy object. It
        is just a workaround as a part of not being able to set them inside
        self.__init__() for the purpose of removing __init__() methods from strategies.
        """
        self.position = selectors.get_position(self.exchange, self.symbol)
        self.broker = Broker(self.position, self.exchange, self.symbol, self.timeframe)

        if self.hp is None and len(self.hyperparameters()) > 0:
            self.hp = {}
            for dna in self.hyperparameters():
                self.hp[dna['name']] = dna['default']
Exemple #16
0
    def update_position(exchange: str, symbol: str, candle: np.ndarray) -> None:
        # get position object
        p = selectors.get_position(exchange, symbol)

        # for extra_route candles, p == None, hence no further action is required
        if p is None:
            return

        price_precision = 0
        if jh.is_live():
          price_precision = selectors.get_exchange(exchange).vars['precisions'][symbol]['price_precision']

        # update position.current_price
        p.current_price = jh.round_price_for_live_mode(candle[2], candle[2], price_precision)
Exemple #17
0
    def __init__(self, attributes=None):
        # id generated by Jesse for database usage
        self.id = ''

        # id generated by market, used in live-trade mode
        self.exchange_id = ''
        # some exchanges might require even further info
        self.vars = {}

        self.symbol = ''
        self.exchange = ''
        self.side = ''
        self.type = ''
        self.flag = ''
        self.qty = 0
        self.price = 0
        self.status = order_statuses.ACTIVE
        self.created_at = None
        self.executed_at = None
        self.canceled_at = None
        self.role = None

        if attributes is None:
            attributes = {}

        for a in attributes:
            setattr(self, a, attributes[a])

        if self.created_at is None:
            self.created_at = jh.now_to_timestamp()

        p = selectors.get_position(self.exchange, self.symbol)
        if p:
            if jh.is_live() and config['env']['notifications']['events']['submitted_orders']:
                self.notify_submission()
            if jh.is_debuggable('order_submission'):
                logger.info(
                    '{} order: {}, {}, {}, {}, ${}'.format(
                        'QUEUED' if self.is_queued else 'SUBMITTED',
                        self.symbol, self.type, self.side, self.qty,
                        round(self.price, 2)
                    )
                )

            p._on_opened_order(self)

        # handle exchange balance for ordered asset
        e = selectors.get_exchange(self.exchange)
        e.on_order_submission(self)
Exemple #18
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 #19
0
    def __init__(self, attributes=None):
        # id generated by Jesse for database usage
        self.id = ''
        # id generated by market
        self.exchange_id = ''
        self.symbol = ''
        self.exchange = ''
        self.side = ''
        self.type = ''
        self.flag = ''
        self.qty = 0
        self.price = 0
        self.status = order_statuses.ACTIVE
        self.created_at = None
        self.executed_at = None
        self.canceled_at = None
        self.role = None

        if attributes is None:
            attributes = {}

        for a in attributes:
            setattr(self, a, attributes[a])

        if self.created_at is None:
            self.created_at = jh.now()

        p = selectors.get_position(self.exchange, self.symbol)
        if p:
            p._on_opened_order(self)

        if jh.is_live() and config['env']['notifications']['events']['submitted_orders']:
            self.notify_submission()

        if jh.is_debuggable('order_submission'):
            logger.info(
                '{} order: {}, {}, {}, {}, ${}'.format(
                    'QUEUED' if self.is_queued else 'SUBMITTED',
                    self.symbol, self.type, self.side, self.qty,
                    round(self.price, 2)
                )
            )
def test_strategy_properties():
    two_routes_backtest('Test19', 'Test19')

    for r in router.routes:
        s: Strategy = r.strategy

        assert s.name == r.strategy_name
        assert s.symbol == r.symbol
        assert s.exchange == r.exchange
        assert s.timeframe == r.timeframe
        assert s.trade is None
        assert s._is_executing is False
        assert s._is_initiated is True
        np.testing.assert_equal(
            s.current_candle,
            store.candles.get_current_candle(r.exchange, r.symbol,
                                             r.timeframe))
        np.testing.assert_equal(
            s.candles,
            store.candles.get_candles(r.exchange, r.symbol, r.timeframe))
        assert s.position == selectors.get_position(r.exchange, r.symbol)
        assert s.orders == store.orders.get_orders(r.exchange, r.symbol)
Exemple #21
0
    def tradable_balance(self, symbol=''):
        if self.type == 'spot':
            if symbol == '':
                raise ValueError
            quote_asset = jh.quote_asset(symbol)
            return self.available_assets[quote_asset]
        else:
            temp_credit = self.assets[self.settlement_currency]
            # we need to consider buy and sell orders of ALL pairs
            # also, consider the value of all open positions
            for asset in self.assets:
                if asset == self.settlement_currency:
                    continue

                position = selectors.get_position(
                    self.name, asset + "-" + self.settlement_currency)
                if position is None:
                    continue

                if position.is_open:
                    # add unrealized PNL
                    temp_credit += position.pnl

                # subtract worst scenario orders' used margin
                sum_buy_orders = (self.buy_orders[asset][:][:, 0] *
                                  self.buy_orders[asset][:][:, 1]).sum()
                sum_sell_orders = (self.sell_orders[asset][:][:, 0] *
                                   self.sell_orders[asset][:][:, 1]).sum()
                if position.is_open:
                    if position.type == 'long':
                        sum_buy_orders += position.value
                    else:
                        sum_sell_orders -= abs(position.value)
                temp_credit -= max(abs(sum_buy_orders), abs(sum_sell_orders))

            return temp_credit
Exemple #22
0
def simulator(
        candles: dict, run_silently: bool, hyperparameters: dict = None
) -> None:
    begin_time_track = time.time()
    key = f"{config['app']['considering_candles'][0][0]}-{config['app']['considering_candles'][0][1]}"
    first_candles_set = candles[key]['candles']
    length = len(first_candles_set)
    # to preset the array size for performance
    try:
        store.app.starting_time = first_candles_set[0][0]
    except IndexError:
        raise IndexError('Check your "warm_up_candles" config value')
    store.app.time = first_candles_set[0][0]

    # initiate strategies
    for r in router.routes:
        # if the r.strategy is str read it from file
        if isinstance(r.strategy_name, str):
            StrategyClass = jh.get_strategy_class(r.strategy_name)
        # else it is a class object so just use it
        else:
            StrategyClass = r.strategy_name

        try:
            r.strategy = StrategyClass()
        except TypeError:
            raise exceptions.InvalidStrategy(
                "Looks like the structure of your strategy directory is incorrect. Make sure to include the strategy INSIDE the __init__.py file."
                "\nIf you need working examples, check out: https://github.com/jesse-ai/example-strategies"
            )
        except:
            raise

        r.strategy.name = r.strategy_name
        r.strategy.exchange = r.exchange
        r.strategy.symbol = r.symbol
        r.strategy.timeframe = r.timeframe

        # read the dna from strategy's dna() and use it for injecting inject hyperparameters
        # first convert DNS string into hyperparameters
        if len(r.strategy.dna()) > 0 and hyperparameters is None:
            hyperparameters = jh.dna_to_hp(r.strategy.hyperparameters(), r.strategy.dna())

        # inject hyperparameters sent within the optimize mode
        if hyperparameters is not None:
            r.strategy.hp = hyperparameters

        # init few objects that couldn't be initiated in Strategy __init__
        # it also injects hyperparameters into self.hp in case the route does not uses any DNAs
        r.strategy._init_objects()

        selectors.get_position(r.exchange, r.symbol).strategy = r.strategy

    # add initial balance
    save_daily_portfolio_balance()

    progressbar = Progressbar(length, step=60)
    for i in range(length):
        # update time
        store.app.time = first_candles_set[i][0] + 60_000

        # add candles
        for j in candles:
            short_candle = candles[j]['candles'][i]
            if i != 0:
                previous_short_candle = candles[j]['candles'][i - 1]
                short_candle = _get_fixed_jumped_candle(previous_short_candle, short_candle)
            exchange = candles[j]['exchange']
            symbol = candles[j]['symbol']

            store.candles.add_candle(short_candle, exchange, symbol, '1m', with_execution=False,
                                     with_generation=False)

            # print short candle
            if jh.is_debuggable('shorter_period_candles'):
                print_candle(short_candle, True, symbol)

            _simulate_price_change_effect(short_candle, exchange, symbol)

            # generate and add candles for bigger timeframes
            for timeframe in config['app']['considering_timeframes']:
                # for 1m, no work is needed
                if timeframe == '1m':
                    continue

                count = jh.timeframe_to_one_minutes(timeframe)
                # until = count - ((i + 1) % count)

                if (i + 1) % count == 0:
                    generated_candle = generate_candle_from_one_minutes(
                        timeframe,
                        candles[j]['candles'][(i - (count - 1)):(i + 1)])
                    store.candles.add_candle(generated_candle, exchange, symbol, timeframe, with_execution=False,
                                             with_generation=False)

        # update progressbar
        if not run_silently and i % 60 == 0:
            progressbar.update()
            sync_publish('progressbar', {
                'current': progressbar.current,
                'estimated_remaining_seconds': progressbar.estimated_remaining_seconds
            })

        # now that all new generated candles are ready, execute
        for r in router.routes:
            count = jh.timeframe_to_one_minutes(r.timeframe)
            # 1m timeframe
            if r.timeframe == timeframes.MINUTE_1:
                r.strategy._execute()
            elif (i + 1) % count == 0:
                # print candle
                if jh.is_debuggable('trading_candles'):
                    print_candle(store.candles.get_current_candle(r.exchange, r.symbol, r.timeframe), False,
                                 r.symbol)
                r.strategy._execute()

        # now check to see if there's any MARKET orders waiting to be executed
        store.orders.execute_pending_market_orders()

        if i != 0 and i % 1440 == 0:
            save_daily_portfolio_balance()

    if not run_silently:
        # print executed time for the backtest session
        finish_time_track = time.time()
        sync_publish('alert', {
            'message': f'Successfully executed backtest simulation in: {round(finish_time_track - begin_time_track, 2)} seconds',
            'type': 'success'
        })

    for r in router.routes:
        r.strategy._terminate()
        store.orders.execute_pending_market_orders()

    # now that backtest is finished, add finishing balance
    save_daily_portfolio_balance()
Exemple #23
0
def simulator(candles, hyper_parameters=None):
    begin_time_track = time.time()
    key = '{}-{}'.format(config['app']['trading_exchanges'][0],
                         config['app']['trading_symbols'][0])
    first_candles_set = candles[key]['candles']
    length = len(first_candles_set)
    # to preset the array size for performance
    store.app.starting_time = first_candles_set[0][0]

    # initiate strategies
    for r in router.routes:
        StrategyClass = jh.get_strategy_class(r.strategy_name)

        # convert DNS string into hyper_parameters
        if r.dna and hyper_parameters is None:
            hyper_parameters = jh.dna_to_hp(StrategyClass.hyper_parameters(),
                                            r.dna)

        r.strategy = StrategyClass()
        r.strategy.name = r.strategy_name
        r.strategy.exchange = r.exchange
        r.strategy.symbol = r.symbol
        r.strategy.timeframe = r.timeframe

        # init few objects that couldn't be initiated in Strategy __init__
        r.strategy._init_objects()

        # inject hyper parameters (used for optimize_mode)
        if hyper_parameters is not None:
            r.strategy.hp = hyper_parameters

        selectors.get_position(r.exchange, r.symbol).strategy = r.strategy

    # add initial balance
    _save_daily_portfolio_balance()

    with click.progressbar(length=length,
                           label='Executing simulation...') as progressbar:
        for i in range(length):
            # update time
            store.app.time = first_candles_set[i][0] + 60_000

            # add candles
            for j in candles:
                short_candle = candles[j]['candles'][i]
                exchange = candles[j]['exchange']
                symbol = candles[j]['symbol']

                store.candles.add_candle(short_candle,
                                         exchange,
                                         symbol,
                                         '1m',
                                         with_execution=False,
                                         with_generation=False)

                # print short candle
                if jh.is_debuggable('shorter_period_candles'):
                    print_candle(short_candle, True, symbol)

                _simulate_price_change_effect(short_candle, exchange, symbol)

                # generate and add candles for bigger timeframes
                for timeframe in config['app']['considering_timeframes']:
                    # for 1m, no work is needed
                    if timeframe == '1m':
                        continue

                    count = jh.timeframe_to_one_minutes(timeframe)
                    until = count - ((i + 1) % count)

                    if (i + 1) % count == 0:
                        generated_candle = generate_candle_from_one_minutes(
                            timeframe,
                            candles[j]['candles'][(i - (count - 1)):(i + 1)])
                        store.candles.add_candle(generated_candle,
                                                 exchange,
                                                 symbol,
                                                 timeframe,
                                                 with_execution=False,
                                                 with_generation=False)

            # update progressbar
            if not jh.is_debugging() and not jh.should_execute_silently(
            ) and i % 60 == 0:
                progressbar.update(60)

            # now that all new generated candles are ready, execute
            for r in router.routes:
                count = jh.timeframe_to_one_minutes(r.timeframe)
                # 1m timeframe
                if r.timeframe == timeframes.MINUTE_1:
                    r.strategy._execute()
                elif (i + 1) % count == 0:
                    # print candle
                    if jh.is_debuggable('trading_candles'):
                        print_candle(
                            store.candles.get_current_candle(
                                r.exchange, r.symbol, r.timeframe), False,
                            r.symbol)
                    r.strategy._execute()

            # now check to see if there's any MARKET orders waiting to be executed
            store.orders.execute_pending_market_orders()

            if i != 0 and i % 1440 == 0:
                _save_daily_portfolio_balance()

    if not jh.should_execute_silently():
        if jh.is_debuggable('trading_candles') or jh.is_debuggable(
                'shorter_period_candles'):
            print('\n')

        # print executed time for the backtest session
        finish_time_track = time.time()
        print(
            'Executed backtest simulation in: ',
            '{} seconds'.format(round(finish_time_track - begin_time_track,
                                      2)))

    for r in router.routes:
        r.strategy._terminate()

    # now that backtest is finished, add finishing balance
    _save_daily_portfolio_balance()
Exemple #24
0
def simulator(candles: Dict[str, Dict[str, Union[str, np.ndarray]]],
              hyperparameters=None) -> None:
    begin_time_track = time.time()
    key = '{}-{}'.format(config['app']['considering_candles'][0][0],
                         config['app']['considering_candles'][0][1])
    first_candles_set = candles[key]['candles']
    length = len(first_candles_set)
    # to preset the array size for performance
    store.app.starting_time = first_candles_set[0][0]
    store.app.time = first_candles_set[0][0]

    # initiate strategies
    for r in router.routes:
        StrategyClass = jh.get_strategy_class(r.strategy_name)

        try:
            r.strategy = StrategyClass()
        except TypeError:
            raise exceptions.InvalidStrategy(
                "Looks like the structure of your strategy directory is incorrect. Make sure to include the strategy INSIDE the __init__.py file."
                "\nIf you need working examples, check out: https://github.com/jesse-ai/example-strategies"
            )
        except:
            raise

        r.strategy.name = r.strategy_name
        r.strategy.exchange = r.exchange
        r.strategy.symbol = r.symbol
        r.strategy.timeframe = r.timeframe

        # inject hyper parameters (used for optimize_mode)
        # convert DNS string into hyperparameters
        if r.dna and hyperparameters is None:
            hyperparameters = jh.dna_to_hp(r.strategy.hyperparameters(), r.dna)

        # inject hyperparameters sent within the optimize mode
        if hyperparameters is not None:
            r.strategy.hp = hyperparameters

        # init few objects that couldn't be initiated in Strategy __init__
        # it also injects hyperparameters into self.hp in case the route does not uses any DNAs
        r.strategy._init_objects()

        selectors.get_position(r.exchange, r.symbol).strategy = r.strategy

    # add initial balance
    save_daily_portfolio_balance()

    with click.progressbar(length=length,
                           label='Executing simulation...') as progressbar:
        for i in range(length):
            # update time
            store.app.time = first_candles_set[i][0] + 60_000

            # add candles
            for j in candles:
                short_candle = candles[j]['candles'][i]
                if i != 0:
                    previous_short_candle = candles[j]['candles'][i - 1]
                    short_candle = _get_fixed_jumped_candle(
                        previous_short_candle, short_candle)
                exchange = candles[j]['exchange']
                symbol = candles[j]['symbol']

                store.candles.add_candle(short_candle,
                                         exchange,
                                         symbol,
                                         '1m',
                                         with_execution=False,
                                         with_generation=False)

                # print short candle
                if jh.is_debuggable('shorter_period_candles'):
                    print_candle(short_candle, True, symbol)

                _simulate_price_change_effect(short_candle, exchange, symbol)

                # generate and add candles for bigger timeframes
                for timeframe in config['app']['considering_timeframes']:
                    # for 1m, no work is needed
                    if timeframe == '1m':
                        continue

                    count = jh.timeframe_to_one_minutes(timeframe)
                    until = count - ((i + 1) % count)

                    if (i + 1) % count == 0:
                        generated_candle = generate_candle_from_one_minutes(
                            timeframe,
                            candles[j]['candles'][(i - (count - 1)):(i + 1)])
                        store.candles.add_candle(generated_candle,
                                                 exchange,
                                                 symbol,
                                                 timeframe,
                                                 with_execution=False,
                                                 with_generation=False)

            # update progressbar
            if not jh.is_debugging() and not jh.should_execute_silently(
            ) and i % 60 == 0:
                progressbar.update(60)

            # now that all new generated candles are ready, execute
            for r in router.routes:
                count = jh.timeframe_to_one_minutes(r.timeframe)
                # 1m timeframe
                if r.timeframe == timeframes.MINUTE_1:
                    r.strategy._execute()
                elif (i + 1) % count == 0:
                    # print candle
                    if jh.is_debuggable('trading_candles'):
                        print_candle(
                            store.candles.get_current_candle(
                                r.exchange, r.symbol, r.timeframe), False,
                            r.symbol)
                    r.strategy._execute()

            # now check to see if there's any MARKET orders waiting to be executed
            store.orders.execute_pending_market_orders()

            if i != 0 and i % 1440 == 0:
                save_daily_portfolio_balance()

    if not jh.should_execute_silently():
        if jh.is_debuggable('trading_candles') or jh.is_debuggable(
                'shorter_period_candles'):
            print('\n')

        # print executed time for the backtest session
        finish_time_track = time.time()
        print(
            'Executed backtest simulation in: ',
            '{} seconds'.format(round(finish_time_track - begin_time_track,
                                      2)))

    for r in router.routes:
        r.strategy._terminate()
        store.orders.execute_pending_market_orders()

    # now that backtest is finished, add finishing balance
    save_daily_portfolio_balance()
Exemple #25
0
def test_backtesting_three_routes():
    reset_config()
    routes = [{
        'exchange': exchanges.SANDBOX,
        'symbol': 'BTC-USDT',
        'timeframe': timeframes.MINUTE_5,
        'strategy': 'Test19'
    }, {
        'exchange': exchanges.SANDBOX,
        'symbol': 'ETH-USDT',
        'timeframe': timeframes.MINUTE_5,
        'strategy': 'Test19'
    }, {
        'exchange': exchanges.SANDBOX,
        'symbol': 'XRP-USDT',
        'timeframe': timeframes.MINUTE_15,
        'strategy': 'Test19'
    }]
    config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'futures'

    candles = {}
    for r in routes:
        key = jh.key(r['exchange'], r['symbol'])
        candles[key] = {
            'exchange': r['exchange'],
            'symbol': r['symbol'],
            'candles': range_candles(5 * 3 * 20)
        }

    # run backtest (dates are fake just to pass)
    backtest_mode.run(False, {}, routes, [], '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 router.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_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