Esempio n. 1
0
    def open(self,
             trader,
             instrument,
             direction,
             order_type,
             order_price,
             quantity,
             take_profit,
             stop_loss,
             leverage=1.0,
             hedging=None):
        """
        Open a position or buy an asset.

        @param hedging If defined use the defined value else use the default from the market.
        """
        order = Order(trader, instrument.market_id)
        order.direction = direction
        order.order_type = order_type
        order.quantity = quantity
        order.leverage = leverage
        order.margin_trade = True
        order.post_only = False

        if order_type == Order.ORDER_LIMIT:
            order.price = order_price

        if hedging:
            order.hedging = hedging

        # generated a reference order id
        trader.set_ref_order_id(order)
        self.create_ref_oid = order.ref_order_id

        self.dir = order.direction

        self.op = order.price  # retains the order price
        self.oq = order.quantity  # ordered quantity

        self.tp = take_profit
        self.sl = stop_loss

        self.leverage = leverage

        self._stats['entry-order-type'] = order.order_type

        if trader.create_order(order, instrument):
            # keep the related create position identifier if available
            self.create_oid = order.order_id
            self.position_id = order.position_id

            if not self.eot and order.created_time:
                # only at the first open
                self.eot = order.created_time

            return True
        else:
            self._entry_state = StrategyTrade.STATE_REJECTED
            return False
Esempio n. 2
0
    def close(self, trader, instrument):
        """
        Close the position and cancel the related orders.
        """
        if self._closing:
            # already closing order
            return False

        if self.create_oid:
            # cancel the remaining buy order
            if trader.cancel_order(self.create_oid):
                self.create_ref_oid = None
                self.create_oid = None

                self._entry_state = StrategyTrade.STATE_CANCELED

        if self.stop_oid:
            # cancel the stop order
            if trader.cancel_order(self.stop_oid):
                self.stop_ref_oid = None
                self.stop_oid = None

        if self.limit_oid:
            # cancel the limit order
            if trader.cancel_order(self.limit_oid):
                self.limit_ref_oid = None

        if self.e - self.x > 0.0:
            # bitmex case no have position id
            order = Order(trader, instrument.market_id)
            order.direction = -self.dir  # neg dir
            order.order_type = Order.ORDER_MARKET
            order.reduce_only = True
            order.quantity = self.e - self.x  # remaining qty
            order.leverage = self.leverage
            order.margin_trade = True

            # generated a reference order id
            trader.set_ref_order_id(order)
            self.stop_ref_oid = order.ref_order_id

            self._stats['stop-order-type'] = order.order_type

            if trader.create_order(order):
                self.stop_oid = order.order_id
                self.stop_order_qty = order.quantity

                # closing order defined
                self._closing = True

                return True
            else:
                self.stop_ref_oid = None
                return False

        return True
Esempio n. 3
0
    def modify_take_profit(self, trader, instrument, limit_price):
        if self.limit_oid:
            # cancel the limit order and create a new one
            if trader.cancel_order(self.limit_oid):
                self.limit_ref_oid = None
                self.limit_oid = None
                self.limit_order_qty = 0.0
            else:
                return False

        if self.e == self.x:
            # all entry qty is filled
            return True

        if self.e < self.x:
            # something wrong but its ok
            return False

        if self.position_id:
            # if not accepted as modification do it as limit order
            if trader.modify_position(self.position_id,
                                      take_profit_price=limit_price):
                self.tp = limit_price
                return True

        elif self.e > 0:
            # only if filled entry partially or totally
            order = Order(self, instrument.market_id)
            order.direction = -self.direction
            order.order_type = Order.ORDER_LIMIT
            order.reduce_only = True
            order.quantity = self.e - self.x  # remaining
            order.price = limit_price
            order.leverage = self.leverage
            order.margin_trade = True

            trader.set_ref_order_id(order)
            self.limit_ref_oid = order.ref_order_id

            self._stats['limit-order-type'] = order.order_type

            if trader.create_order(order):
                self.limit_oid = order.order_id
                self.limit_order_qty = order.quantity

                self.last_tp_ot[0] = order.created_time
                self.last_tp_ot[1] += 1

                self.tp = limit_price

                return True
            else:
                self.limit_ref_oid = None
                self.limit_order_qty = 0.0

        return False
Esempio n. 4
0
    def open(self,
             trader,
             market_id,
             direction,
             order_type,
             order_price,
             quantity,
             take_profit,
             stop_loss,
             leverage=1.0,
             hedging=None):
        """
        Open a position or buy an asset.

        @param hedging If defined use the defined value else use the default from the market.
        """
        order = Order(trader, market_id)
        order.direction = direction
        order.order_price = order_price
        order.order_type = order_type
        order.quantity = quantity
        order.leverage = leverage

        if hedging:
            order.hedging = hedging

        # generated a reference order id
        trader.set_ref_order_id(order)
        self.create_ref_oid = order.ref_order_id

        self.dir = order.direction

        self.op = order.order_price  # retains the order price
        self.oq = order.quantity  # ordered quantity

        self.tp = take_profit
        self.sl = stop_loss

        self._stats['entry-maker'] = not order.is_market()

        if trader.create_order(order):
            # keep the related create position identifier if available
            self.position_id = order.position_id

            if not self.eot and order.created_time:
                # only at the first open
                self.eot = order.created_time

            return True
        else:
            self.create_ref_oid = None

        return False
Esempio n. 5
0
    def open(self,
             trader,
             market_id,
             direction,
             order_type,
             order_price,
             quantity,
             take_profit,
             stop_loss,
             leverage=1.0,
             hedging=None):
        """
        Buy an asset.
        """
        if self._entry_state != StrategyTrade.STATE_NEW:
            return False

        order = Order(trader, market_id)
        order.direction = direction
        order.price = order_price
        order.order_type = order_type
        order.quantity = quantity
        order.leverage = leverage

        # if need to retry @todo or cancel
        # self._market_id = market_id
        # self._order_type = order_type
        # self._leverage = leverage

        # generated a reference order id
        trader.set_ref_order_id(order)
        self.entry_ref_oid = order.ref_order_id

        self.dir = order.direction

        self.op = order.price  # retains the order price
        self.oq = order.quantity  # ordered quantity

        self.tp = take_profit
        self.sl = stop_loss

        self._stats['entry-maker'] = not order.is_market()

        if trader.create_order(order):
            if not self.eot and order.created_time:
                # only at the first open
                self.eot = order.created_time

            return True
        else:
            self._entry_state = StrategyTrade.STATE_REJECTED
            return False
Esempio n. 6
0
    def modify_take_profit(self, trader, instrument, limit_price):
        if self.limit_oid:
            # cancel the limit order and create a new one
            if trader.cancel_order(self.limit_oid, instrument):
                self.limit_ref_oid = None
                self.limit_oid = None
                self.limit_order_qty = 0.0
            else:
                return self.ERROR

        if self.e == self.x:
            # all entry qty is filled
            return self.NOTHING_TO_DO

        if self.e < self.x:
            # something wrong but its ok
            return self.NOTHING_TO_DO

        if self.e > 0 and limit_price > 0.0:
            # only if filled entry partially or totally
            order = Order(self, instrument.market_id)
            order.direction = -self.direction
            order.order_type = Order.ORDER_LIMIT
            order.reduce_only = True
            order.quantity = self.e - self.x  # remaining
            order.price = limit_price
            order.leverage = self.leverage
            order.margin_trade = True

            trader.set_ref_order_id(order)
            self.limit_ref_oid = order.ref_order_id

            self._stats['take-profit-order-type'] = order.order_type

            if trader.create_order(order, instrument):
                self.limit_oid = order.order_id
                self.limit_order_qty = order.quantity

                self.last_tp_ot[0] = order.created_time
                self.last_tp_ot[1] += 1

                self.tp = limit_price

                return self.ACCEPTED
            else:
                self.limit_ref_oid = None
                self.limit_order_qty = 0.0

                return self.REJECTED

        return self.NOTHING_TO_DO
Esempio n. 7
0
    def open(self,
             trader,
             instrument,
             direction,
             order_type,
             order_price,
             quantity,
             take_profit,
             stop_loss,
             leverage=1.0,
             hedging=None):
        """
        Open a position or buy an asset.
        """
        order = Order(trader, instrument.market_id)
        order.direction = direction
        order.price = order_price
        order.order_type = order_type
        order.quantity = quantity
        order.post_only = False
        order.margin_trade = True
        order.leverage = leverage

        # generated a reference order id
        trader.set_ref_order_id(order)
        self.create_ref_oid = order.ref_order_id

        self.dir = order.direction

        self.op = order.price  # retains the order price
        self.oq = order.quantity  # ordered quantity

        self.tp = take_profit
        self.sl = stop_loss

        self.leverage = leverage

        self._stats['entry-order-type'] = order.order_type

        if trader.create_order(order, instrument):
            self.position_id = order.position_id  # might be market-id

            if not self.eot and order.created_time:
                self.eot = order.created_time

            return True
        else:
            self._entry_state = StrategyTrade.STATE_REJECTED
            return False
Esempio n. 8
0
    def modify_stop_loss(self, trader, instrument, stop_price):
        if self.stop_oid:
            # cancel the stop order and create a new one
            if trader.cancel_order(self.stop_oid):
                self.stop_ref_oid = None
                self.stop_oid = None
            else:
                return False

        if self.e == self.x:
            # all entry qty is filled
            return True

        if self.e < self.x:
            # something wrong but its ok
            return False

        if self.e > 0 and stop_price > 0.0:
            # only if filled entry partially or totally
            order = Order(self, instrument.market_id)
            order.direction = -self.direction
            order.order_type = Order.ORDER_STOP
            order.reduce_only = True
            order.quantity = self.e - self.x  # remaining
            order.stop_price = stop_price
            order.leverage = self.leverage
            order.margin_trade = True

            trader.set_ref_order_id(order)
            self.stop_ref_oid = order.ref_order_id

            self._stats['stop-order-type'] = order.order_type

            if trader.create_order(order):
                self.stop_oid = order.order_id
                self.stop_order_qty = order.quantity

                self.last_sl_ot[0] = order.created_time
                self.last_sl_ot[1] += 1

                self.sl = stop_price

                return True
            else:
                self.stop_ref_oid = None
                self.stop_order_qty = 0.0

        return False
Esempio n. 9
0
    def open(self,
             trader,
             market_id,
             direction,
             order_type,
             order_price,
             quantity,
             take_profit,
             stop_loss,
             leverage=1.0,
             hedging=None):
        """
        Open a position or buy an asset.
        """
        order = Order(trader, market_id)
        order.direction = direction
        order.order_price = order_price
        order.order_type = order_type
        order.quantity = quantity
        order.leverage = leverage

        # generated a reference order id
        trader.set_ref_order_id(order)
        self.create_ref_oid = order.ref_order_id

        self.dir = order.direction

        self.op = order.order_price  # retains the order price
        self.oq = order.quantity  # ordered quantity

        self.tp = take_profit
        self.sl = stop_loss

        self._stats['entry-maker'] = not order.is_market()

        if trader.create_order(order):
            self.position_id = order.position_id  # might be market-id

            if not self.eot and order.created_time:
                self.eot = order.created_time

            return True
        else:
            self.create_ref_oid = None

        return False
Esempio n. 10
0
    def modify_stop_loss(self, trader, instrument, stop_price):
        if self.stop_oid:
            # cancel the stop order and create a new one
            if trader.cancel_order(self.stop_oid, instrument):
                self.stop_ref_oid = None
                self.stop_oid = None
            else:
                return self.ERROR

        if self.e - self.x > 0.0:
            # only if filled entry partially or totally
            order = Order(self, instrument.market_id)
            order.direction = -self.direction
            order.order_type = Order.ORDER_STOP
            order.reduce_only = True
            order.quantity = self.e - self.x  # remaining
            order.stop_price = stop_price
            order.margin_trade = True
            order.leverage = self.leverage

            trader.set_ref_order_id(order)
            self.stop_ref_oid = order.ref_order_id

            self._stats['stop-order-type'] = order.order_type

            if trader.create_order(order, instrument):
                self.stop_oid = order.order_id
                self.stop_order_qty = order.quantity

                self.last_stop_ot[0] = order.created_time
                self.last_stop_ot[1] += 1

                self.sl = stop_price

                return self.ACCEPTED
            else:
                self.stop_ref_oid = None
                self.stop_order_qty = 0.0

                return self.REJECTED

        return self.NOTHING_TO_DO
Esempio n. 11
0
    def modify_take_profit(self, trader, instrument, limit_price):
        if self.limit_oid:
            # cancel the limit order and create a new one
            if trader.cancel_order(self.limit_oid):
                self.limit_ref_oid = None
                self.limit_oid = None
                self.limit_order_qty = 0.0
            else:
                return False

        if self.e - self.x > 0.0:
            # only if filled entry partially or totally
            order = Order(self, instrument.market_id)
            order.direction = -self.direction
            order.order_type = Order.ORDER_LIMIT
            order.reduce_only = True
            order.quantity = self.e - self.x  # remaining
            order.price = limit_price
            order.margin_trade = True
            order.leverage = self.leverage

            trader.set_ref_order_id(order)
            self.limit_ref_oid = order.ref_order_id

            self._stats['limit-order-type'] = order.order_type

            if trader.create_order(order):
                self.limit_oid = order.order_id
                self.limit_order_qty = order.quantity

                self.last_tp_ot[0] = order.created_time
                self.last_tp_ot[1] += 1

                self.tp = limit_price

                return True
            else:
                self.limit_ref_oid = None
                self.limit_order_qty = 0.0

        return False
Esempio n. 12
0
    def close_position(self, position_or_id, market=True, limit_price=None):
        """
        Close an existing position.
        Market is default, take care of the fee.
        Limit price can be defined but then it will create a limit order in the opposite direction in some broker
        and modify the position in some other (depends of the mode hedging...).
        """
        if type(position_or_id) is str:
            position = self._positions.get(position_or_id)
        else:
            position = position_or_id

        if position is None or not position.is_opened:
            return False

        # market stop order
        order = Order(self, position.symbol)
        order.direction = position.close_direction()
        order.order_type = Order.ORDER_MARKET
        order.quantity = position.quantity  # fully close
        order.leverage = position.leverage  # same as open

        # simply create an order in the opposite direction
        return self.create_order(order)
Esempio n. 13
0
def close_position(trader,
                   market,
                   position,
                   close_exec_price,
                   order_type=Order.ORDER_LIMIT):
    """
    Close a position.
    """
    if not position:
        return False

    trader.lock()

    if not position.is_opened():
        trader.unlock()
        return False

    # create an order for the close
    order = Order(trader, position.symbol)
    order.set_position_id(position.position_id)

    order.direction = position.close_direction()
    order.order_type = order_type

    if order_type == Order.ORDER_LIMIT:
        order.price = close_exec_price

    order.quantity = position.quantity
    order.leverage = position.leverage

    order.close_only = True
    order.reduce_only = True

    # increase or reduce the current position
    org_quantity = position.quantity
    exec_price = 0.0

    # price difference depending of the direction
    delta_price = 0
    if position.direction == Position.LONG:
        delta_price = close_exec_price - position.entry_price
    elif position.direction == Position.SHORT:
        delta_price = position.entry_price - close_exec_price

    # keep for percent calculation
    prev_entry_price = position.entry_price or close_exec_price
    leverage = order.leverage

    # most of thoose data rarely change except the base_exchange_rate
    value_per_pip = market.value_per_pip
    contract_size = market.contract_size
    lot_size = market.lot_size
    one_pip_means = market.one_pip_means
    base_exchange_rate = market.base_exchange_rate
    margin_factor = market.margin_factor

    realized_position_cost = 0.0  # realized cost of the position in base currency

    # effective meaning of delta price in base currency
    effective_price = (delta_price / one_pip_means) * value_per_pip

    # in base currency
    position_gain_loss = 0.0

    # the position is closed, exact quantity in the opposite direction
    position_gain_loss = effective_price * position.quantity
    position.quantity = 0.0
    position.exit_price = close_exec_price

    # directly executed quantity
    order.executed = order.quantity
    exec_price = close_exec_price

    realized_position_cost = market.effective_cost(order.quantity,
                                                   close_exec_price)
    margin_cost = market.margin_cost(order.quantity, close_exec_price)

    # and decrease used margin
    trader.account.free_margin(margin_cost)

    # transaction time is current timestamp
    order.transact_time = trader.timestamp

    if position_gain_loss != 0.0 and realized_position_cost > 0.0:
        # ratio
        gain_loss_rate = position_gain_loss / realized_position_cost
        relative_gain_loss_rate = delta_price / prev_entry_price

        # if maker close (limit+post-order) (for now same as market)
        position.profit_loss = position_gain_loss
        position.profit_loss_rate = gain_loss_rate

        # if taker close (market)
        position.profit_loss_market = position_gain_loss
        position.profit_loss_market_rate = gain_loss_rate

        trader.account.add_realized_profit_loss(position_gain_loss /
                                                base_exchange_rate)

        # display only for debug
        if position_gain_loss > 0.0:
            Terminal.inst().high(
                "Close profitable position with %.2f on %s (%.2fpips) (%.2f%%) at %s"
                % (position_gain_loss, order.symbol,
                   delta_price / one_pip_means, gain_loss_rate * 100.0,
                   market.format_price(close_exec_price)),
                view='debug')
        elif position_gain_loss < 0.0:
            Terminal.inst().low(
                "Close loosing position with %.2f on %s (%.2fpips) (%.2f%%) at %s"
                % (position_gain_loss, order.symbol,
                   delta_price / one_pip_means, gain_loss_rate * 100.0,
                   market.format_price(close_exec_price)),
                view='debug')
    else:
        gain_loss_rate = 0.0

    # unlock before notify signals
    trader.unlock()

    #
    # order signal (SIGNAL_ORDER_OPENED+DELETED because we assume fully completed)
    #

    order_data = {
        'id': order.order_id,
        'symbol': order.symbol,
        'type': order.order_type,
        'direction': order.direction,
        'timestamp': order.created_time,
        'quantity': order.quantity,
        'price': order.price,
        'stop-price': order.stop_price,
        'stop-loss': order.stop_loss,
        'take-profit': order.take_profit,
        'time-in-force': order.time_in_force
    }

    # signal as watcher service (opened + fully traded qty)
    trader.service.watcher_service.notify(
        Signal.SIGNAL_ORDER_OPENED, trader.name,
        (order.symbol, order_data, order.ref_order_id))

    order_data = {
        'id': order.order_id,
        'symbol': order.symbol,
        'type': order.order_type,
        'trade-id': 0,
        'direction': order.direction,
        'timestamp': order.transact_time,
        'quantity': order.quantity,
        'price': order.price,
        'stop-price': order.stop_price,
        'exec-price': exec_price,
        'avg-price': position.entry_price,
        'filled': order.executed,
        'cumulative-filled': order.executed,
        'quote-transacted': realized_position_cost,  # its margin
        'stop-loss': order.stop_loss,
        'take-profit': order.take_profit,
        'time-in-force': order.time_in_force,
        'commission-amount': 0,
        'commission-asset': trader.account.currency
    }

    trader.service.watcher_service.notify(
        Signal.SIGNAL_ORDER_TRADED, trader.name,
        (order.symbol, order_data, order.ref_order_id))

    #
    # position signal
    #

    # closed position
    position_data = {
        'id': position.position_id,
        'symbol': position.symbol,
        'direction': position.direction,
        'timestamp': order.transact_time,
        'quantity': 0,
        'avg-entry-price': position.entry_price,
        'avg-exit-price': position.exit_price,
        'exec-price': exec_price,
        'stop-loss': None,
        'take-profit': None,
        'profit-loss': position.profit_loss,
        'profit-loss-currency': market.quote
    }

    trader.service.watcher_service.notify(
        Signal.SIGNAL_POSITION_DELETED, trader.name,
        (order.symbol, position_data, order.ref_order_id))

    # and then deleted order
    trader.service.watcher_service.notify(Signal.SIGNAL_ORDER_DELETED,
                                          trader.name,
                                          (order.symbol, order.order_id, ""))

    position.exit(exec_price)

    return True
Esempio n. 14
0
    def close_position(self,
                       position_id,
                       market_or_instrument,
                       direction,
                       quantity,
                       market=True,
                       limit_price=None):
        if not position_id or not market_or_instrument:
            return False

        trader_market = self._markets.get(market_or_instrument.market_id)
        if not trader_market:
            error_logger.error(
                "Trader %s refuse to close position because the market %s is not found"
                % (self.name, market_or_instrument.market_id))
            return False

        result = False

        with self._mutex:
            # retrieve the position
            position = self._positions.get(position_id)

            if position and position.is_opened():
                # market stop order
                order = Order(self, position.symbol)
                order.set_position_id(position_id)

                order.direction = position.close_direction()

                if limit_price:
                    order.order_type = Order.ORDER_LIMIT
                    order.price = limit_price
                else:
                    order.order_type = Order.ORDER_MARKET

                order.quantity = position.quantity  # fully close
                order.leverage = position.leverage  # same as open

                order.close_only = True
                order.reduce_only = True

                #
                # price according to order type
                #

                bid_price = 0
                ofr_price = 0

                if order.order_type == Order.ORDER_LIMIT:
                    bid_price = order.price
                    ofr_price = order.price

                elif order.order_type == Order.ORDER_MARKET:
                    bid_price = trader_market.bid
                    ofr_price = trader_market.ofr

                # open long are executed on bid and short on ofr, close the inverse
                if order.direction == Position.LONG:
                    open_exec_price = ofr_price  # bid_price
                    close_exec_price = bid_price  # ofr_price
                elif order.direction == Position.SHORT:
                    open_exec_price = bid_price  # ofr_price
                    close_exec_price = ofr_price  # bid_price
                else:
                    logger.error("Unsupported direction")
                    return False

                if not open_exec_price or not close_exec_price:
                    logger.error("No order execution price")
                    return False

                if self._slippage > 0.0:
                    # @todo deferred to update
                    return False
                else:
                    # immediate execution of the order
                    if trader_market.has_position:
                        # close isolated position
                        result = close_position(self, trader_market, position,
                                                close_exec_price,
                                                Order.ORDER_MARKET)
                    else:
                        # close position (could be using FIFO method)
                        result = exec_margin_order(self, order, trader_market,
                                                   open_exec_price,
                                                   close_exec_price)
            else:
                result = False

        return result
Esempio n. 15
0
    def __update_reversal(self, instrument):
        # consts
        MIN_SCORE = 4 * 60  # min score to reach to validate an order
        BSD_SCORE_FACTOR = 2  # 2,3
        CBO_SCORE_FACTOR = 2  # 2,3
        RSI_SCORE_FACTOR = 0.5  # 0.5,1,2
        RSI_TREND_SCORE_FACTOR = 1  # 0.5,1,2,4
        EMA_VWMA_CROSS_SCORE_FACTOR = 8000  # 5000,8000
        VWMA_PRICE_CROSS_SCORE_FACTOR = 2000  # 2000,4000
        EMA_VWM_BONUS_SCORE = 2  # 1,2,3,5
        TIME_SCORE_REGRESSION_FACTOR = 0.75  # 0.375,0.5,0.75
        RSI_LOW = 30  # 25,30,35
        RSI_HIGH = 70  # 65,70,75

        # @todo a plot of the account balance and % gain/loss of each trade

        # process in 1 minute, retrieve analysis data instrument
        strategy_trader = self._strategy_traders.get(instrument)

        # compute with the max samples
        num_samples = instrument.num_samples(Instrument.TF_MIN)
        depth = min(self.depth, num_samples)
        last_prices = instrument.last_prices(Instrument.TF_MIN,
                                             Instrument.PRICE_CLOSE, depth)
        last_volumes = instrument.last_volumes(Instrument.TF_MIN, depth)

        # current timestamp
        timestamp = self.timestamp

        # instrument.last_candles(Instrument.TF_MIN, depth)
        # @todo Typical price is attained by taking adding the high, low and close, and dividing by three: (H+L+C)/3

        if depth < self.min_depth:
            # not enought samples
            return

        rsi = strategy_trader.rsi.compute(last_prices)
        sma = strategy_trader.sma.compute(last_prices)
        ema = strategy_trader.ema.compute(last_prices)
        vwma = strategy_trader.vwma.compute(last_prices, last_volumes)

        #
        # scorify
        #

        bsd_score = 0
        cbo_score = 0
        rsi_score = 0
        ema_vwma_score = 0
        ema_vwma_bonus_score = 0
        price_vwma_score = 0

        if strategy_trader.blueskyday:
            if strategy_trader.blueskyday[-1].direction == Position.LONG:
                bsd_score = BSD_SCORE_FACTOR
            elif strategy_trader.blueskyday[-1].direction == Position.SHORT:
                bsd_score = -BSD_SCORE_FACTOR

        if strategy_trader.channelbreakout:
            if strategy_trader.channelbreakout[-1].direction == Position.LONG:
                cbo_score = CBO_SCORE_FACTOR
            elif strategy_trader.channelbreakout[
                    -1].direction == Position.SHORT:
                cbo_score = -CBO_SCORE_FACTOR

        # rsi 30/70, gives strong signals
        # @todo be we could compute it on two tf (the last 14N and the more global at depth level to have two trends)
        rsi_argmin = np.argmin(rsi)
        rsi_argmax = np.argmax(rsi)

        # trend of the rsi or MM
        if rsi_argmin < rsi_argmax and rsi[rsi_argmin] < rsi[rsi_argmax]:  # ++
            rsi_trend = (rsi[rsi_argmax] +
                         rsi[rsi_argmin]) / (rsi[rsi_argmax] - rsi[rsi_argmin])
        elif rsi_argmax < rsi_argmin and rsi[rsi_argmax] > rsi[
                rsi_argmin]:  ## --
            rsi_trend = (rsi[rsi_argmin] +
                         rsi[rsi_argmax]) / (rsi[rsi_argmin] - rsi[rsi_argmax])
        else:
            rsi_trend = 0

        if rsi[-1] < RSI_LOW:
            rsi_score = (RSI_LOW - rsi[-1]) * RSI_SCORE_FACTOR  # ++
            if rsi_trend > 0:
                rsi_score += rsi_trend * RSI_TREND_SCORE_FACTOR
        elif rsi[-1] > RSI_HIGH:
            rsi_score = (RSI_HIGH - rsi[-1]) * RSI_SCORE_FACTOR
            if rsi_trend < 0:
                rsi_score += rsi_trend * RSI_TREND_SCORE_FACTOR

        # prev = rsi[0]
        # for (i, v) in enumerate(rsi):
        #   if v < prev and v < RSI_LOW:
        #       longs.append((i, last_prices[i]))
        #       prev = v
        #   elif v > prev and v > RSI_HIGH:
        #       shorts.append((i, last_prices[i]))
        #       prev = v

        # ema/vwma crossing
        ema_vwma_score = (
            ema[-1] - vwma[-1]) / last_prices[-1] * EMA_VWMA_CROSS_SCORE_FACTOR

        # vwma/price crossing
        price_vwma_score = (last_prices[-1] - vwma[-1]
                            ) / last_prices[-1] * VWMA_PRICE_CROSS_SCORE_FACTOR

        # if last_prices[-1] > vwma[-1]:
        #   strategy_trader.scores[-1] += 1
        # elif last_prices[-1] < vwma[-1]:
        #   strategy_trader.scores[-1] -= 1

        # ema/vwma crossing and vwmap/price more score !!
        if ema[-1] > vwma[-1] and last_prices[-1] > vwma[-1]:
            ema_vwma_bonus_score = EMA_VWM_BONUS_SCORE
        elif ema[-1] < vwma[-1] and last_prices[-1] < vwma[-1]:
            ema_vwma_bonus_score = -EMA_VWM_BONUS_SCORE

        # support/resistance signal
        # @todo and then scores +-= 2

        # price delta min including spread, have to determine if the price can vary of a minimal size
        # @todo

        # confirmation on N candles, and don't take care of pyramided orders
        total_score = rsi_score + ema_vwma_score + price_vwma_score + ema_vwma_bonus_score + bsd_score + cbo_score

        #
        # score tuning
        #

        # store the total score
        strategy_trader.scores[-1] = total_score
        final_score = total_score

        # average of the two last score and increase the last, score is exp if signals are in the trend
        if len(strategy_trader.scores) > 2:
            final_score = np.average(strategy_trader.scores[-2:])
            final_score += strategy_trader.scores[-2]

        # and store it
        strategy_trader.scores[-1] = final_score

        # handle a score convergence to avoid multiple signals
        if (strategy_trader.cur_score > 0
                and final_score > 0) or (strategy_trader.cur_score < 0
                                         and final_score < 0):
            # cancel all
            # strategy_trader.scores = [0]

            # or ignore
            # strategy_trader.scores[-1] = 0

            # or take 75% of the previous score to minimize its impact progressively
            # strategy_trader.scores[-1] = strategy_trader.scores[-2] * TIME_SCORE_REGRESSION_FACTOR

            # or keep only 37.5% of it
            strategy_trader.scores[-1] *= TIME_SCORE_REGRESSION_FACTOR * 0.5

            # keep as final score or nullify
            final_score = strategy_trader.scores[-1]

        # handle a score divergence
        # if (rsi_score > 0 and ema_vwma_score < 0) or (rsi_score < 0 and ema_vwma_bonus_score > 0):
        #       total_score *= 0.25

        # limit strategy_trader.scores len to max depth
        if len(strategy_trader.scores) > self.depth:
            strategy_trader.scores = strategy_trader.scores[
                len(strategy_trader.scores) - self.depth:]

        #
        # pass an order if score is accepted
        #

        if abs(final_score) >= MIN_SCORE:
            # keep apart the current score
            strategy_trader.cur_score = final_score

            if final_score > 0:
                strategy_trader.longs.append((timestamp, last_prices[-1]))
            elif final_score < 0:
                strategy_trader.shorts.append((timestamp, last_prices[-1]))

            date_str = datetime.fromtimestamp(timestamp).strftime(
                '%Y-%m-%d %H:%M:%S')
            direction = Position.LONG if final_score > 0 else Position.SHORT

            # create an order an post it
            if final_score > 0:
                Terminal.inst().notice(
                    "> Strategy %s LONG %s%s at price %.4f on %s" %
                    (self.name, instrument.trade_quantity,
                     instrument.market_id, last_prices[-1], date_str))
            else:
                Terminal.inst().notice(
                    "> Strategy %s SHORT %s%s at price %.4f on %s" %
                    (self.name, instrument.trade_quantity,
                     instrument.market_id, last_prices[-1], date_str))

            trader = self.trader()
            if trader:
                order = Order(trader, instrument.market_id)
                order.direction = direction
                order.price = last_prices[-1]

                # depends of the instrument and the account, and not always necessary, but always in paper trader
                order.leverage = instrument.leverage

                positions = trader.positions(instrument.market_id)

                current_opposite_qty = 0.0
                current_same_qty = 0.0

                for position in positions:
                    # strategy does a reversal (and quantity are always positives)
                    if position.direction != direction:
                        # opposit directions ?
                        current_opposite_qty += position.quantity  # need to close that
                    else:
                        # or same direction ?
                        current_same_qty += position.quantity

                # trading quantity + what we have in opposite direction - what we already have in the same direction
                if self._pyramided >= 1:
                    order.quantity = instrument.trade_quantity + current_opposite_qty - current_same_qty  # @todo
                else:
                    order.quantity = instrument.trade_quantity + current_opposite_qty - current_same_qty

                if order.quantity > 0:
                    # @todo debug only
                    Terminal.inst().info(
                        "Do order %s %s with %s" %
                        (instrument.market_id, 'SHORT' if direction
                         == Position.SHORT else 'LONG', order.quantity))
                    trader.create_order(order)

            # consumes buy sell signals
            # @todo could put previous scores into history
            # strategy_trader.scores = [0]
            strategy_trader.blueskyday = []
            strategy_trader.channelbreakout = []
        else:
            # append the next score entry at 0
            strategy_trader.scores.append(0)

        #
        # charting
        #

        if strategy_trader.chart is None and Charting.inst():
            # create the chart if necessary
            strategy_trader.chart = Charting.inst().chart(
                "%s on %s" % (self.name, instrument.symbol))

        rechart = strategy_trader.chart.can_redraw

        if rechart:
            longs = []
            shorts = []

            # take only in depth longs and shorts
            for long in strategy_trader.longs:
                if long[0] + depth * Instrument.TF_MIN >= timestamp:
                    longs.append(
                        ((long[0] + depth * Instrument.TF_MIN - timestamp) /
                         Instrument.TF_MIN, long[1]))

            for short in strategy_trader.shorts:
                if short[0] + depth * Instrument.TF_MIN >= timestamp:
                    shorts.append(
                        ((short[0] + depth * Instrument.TF_MIN - timestamp) /
                         Instrument.TF_MIN, short[1]))

            # @todo send a stream with the last values or/and updated ranges/objects
            strategy_trader.chart.set_range(0, depth)

            strategy_trader.chart.plot_price_serie(0, last_prices)
            strategy_trader.chart.plot_price_serie(1, sma)
            strategy_trader.chart.plot_price_serie(2, ema)
            strategy_trader.chart.plot_price_serie(3, vwma)
            strategy_trader.chart.annotate_price(0, longs, 'g^')
            strategy_trader.chart.annotate_price(1, shorts, 'r^')

            strategy_trader.chart.plot_serie(1, 0, rsi)
            strategy_trader.chart.plot_serie(1, 1, [30] * len(rsi))
            strategy_trader.chart.plot_serie(1, 2, [70] * len(rsi))
            # strategy_trader.chart.plot_serie(2, 0, mmt)
            strategy_trader.chart.draw()
Esempio n. 16
0
File: trader.py Progetto: rptrk/siis
    def close_position(self, position_id, market=True, limit_price=None):
        if not self._activity:
            return False

        result = False

        self.lock()
        position = self._positions.get(position_id)

        if position and position.is_opened():
            # market stop order
            order = Order(self, position.symbol)
            order.set_position_id(position_id)

            order.direction = position.close_direction()

            if market and limit_price:
                order.order_type = Order.ORDER_LIMIT
                order.price = limit_price
            else:
                order.order_type = Order.ORDER_MARKET

            order.quantity = position.quantity  # fully close
            order.leverage = position.leverage  # same as open

            order.close_only = True
            order.reduce_only = True

            self.unlock()

            #
            # price according to order type
            #

            market = self.market(order.symbol)

            bid_price = 0
            ofr_price = 0

            if order.order_type == Order.ORDER_LIMIT:
                bid_price = order.price
                ofr_price = order.price

            elif order.order_type == Order.ORDER_MARKET:
                bid_price = market.bid
                ofr_price = market.ofr

            # open long are executed on bid and short on ofr, close the inverse
            if order.direction == Position.LONG:
                open_exec_price = ofr_price  # bid_price
                close_exec_price = bid_price  # ofr_price
            elif order.direction == Position.SHORT:
                open_exec_price = bid_price  # ofr_price
                close_exec_price = ofr_price  # bid_price
            else:
                logger.error("Unsupported direction")
                return False

            if not open_exec_price or not close_exec_price:
                logger.error("No order execution price")
                return False

            if self._slippage > 0.0:
                # @todo
                return False
            else:
                # immediate execution of the order
                result = exec_margin_order(self, order, market, open_exec_price, close_exec_price)
        else:
            self.unlock()
            result = False         

        return result