コード例 #1
0
 def dumps_notify_entry(self, timestamp, strategy_trader):
     """
     Dumps to dict for notify/history.
     """
     return {
         'version': self.version(),
         'trade': self.trade_type_to_str(),
         'id': self.id,
         'app-name': strategy_trader.strategy.name,
         'app-id': strategy_trader.strategy.identifier,
         'timestamp': timestamp,
         'symbol': strategy_trader.instrument.market_id,
         'way': "entry",
         'entry-timeout': timeframe_to_str(self._entry_timeout),
         'expiry': self._expiry,
         'timeframe': timeframe_to_str(self._timeframe),
         'is-user-trade': self._user_trade,
         'comment': self._comment,
         'direction': self.direction_to_str(),
         'order-price': strategy_trader.instrument.format_price(self.op),
         'order-qty': strategy_trader.instrument.format_quantity(self.oq),
         'stop-loss-price':
         strategy_trader.instrument.format_price(self.sl),
         'take-profit-price':
         strategy_trader.instrument.format_price(self.tp),
         'avg-entry-price':
         strategy_trader.instrument.format_price(self.aep),
         'entry-open-time': self.dump_timestamp(self.eot),
         'stats': {
             'entry-order-type':
             order_type_to_str(self._stats['entry-order-type']),
         }
     }
コード例 #2
0
ファイル: strategysignal.py プロジェクト: rptrk/siis
    def __str__(self):
        mydate = datetime.fromtimestamp(self.ts)
        date_str = mydate.strftime('%Y-%m-%d %H:%M:%S')

        return "tf=%s ts=%s signal=%s dir=%s p=%s sl=%s tp=%s %s" % (
            timeframe_to_str(self.timeframe), date_str, self.signal_type_str(),
            self.direction_str(), self.p, self.sl, self.tp, self.comment)
コード例 #3
0
 def __repr__(self):
     return "%s bid %s/%s/%s/%s ofr %s/%s/%s/%s" % (
         timeframe_to_str(self._timeframe),
         self._bid_open,
         self._bid_high,
         self._bid_low,
         self._bid_close,
         self._ofr_open,
         self._ofr_high,
         self._ofr_low,
         self._ofr_close)
コード例 #4
0
ファイル: strategytrader.py プロジェクト: venkiiee/siis
    def update_trades(self, timestamp):
        """
        Update managed trades per instruments and delete terminated trades.
        """
        if not self.trades:
            return

        trader = self.strategy.trader()

        #
        # for each trade check if the TP or SL is reached and trigger if necessary
        #

        with self._trade_mutex:
            for trade in self.trades:

                #
                # managed operation
                #

                if trade.has_operations():
                    mutated = False

                    for operation in trade.operations:
                        mutated |= operation.test_and_operate(trade, self.instrument, trader)

                    if mutated:
                        trade.cleanup_operations()

                #
                # active trade
                #

                if trade.is_active():
                    # for statistics usage
                    trade.update_stats(self.instrument.close_exec_price(trade.direction), timestamp)

                #
                # asset trade
                #

                if trade.trade_type == StrategyTrade.TRADE_BUY_SELL:
                    if trade.is_closed():
                        continue

                    # process only on active trades
                    if not trade.is_active():
                        # @todo timeout if not filled before condition...
                        continue

                    if trade.is_closing():
                        continue

                    if not self.instrument.tradeable:
                        continue

                    if trade.is_dirty:
                        # entry quantity changed need to update the exits orders
                        trade.update_dirty(trader, self.instrument)

                    # potential order exec close price (always close a long)
                    close_exec_price = self.instrument.close_exec_price(Order.LONG)

                    if (trade.tp > 0) and (close_exec_price >= trade.tp) and not trade.has_limit_order():
                        # take profit trigger stop, close at market (taker fee)
                        if trade.close(trader, self.instrument) > 0:
                            trade.exit_reason = trade.REASON_TAKE_PROFIT_MARKET

                    elif (trade.sl > 0) and (close_exec_price <= trade.sl) and not trade.has_stop_order():
                        # stop loss trigger stop, close at market (taker fee)
                        if trade.close(trader, self.instrument) > 0:
                            trade.exit_reason = trade.REASON_STOP_LOSS_MARKET

                #
                # margin trade
                #

                elif trade.trade_type in (StrategyTrade.TRADE_MARGIN, StrategyTrade.TRADE_POSITION, StrategyTrade.TRADE_IND_MARGIN):
                    # process only on active trades
                    if not trade.is_active():
                        # @todo timeout if not filled before condition...
                        continue

                    if trade.is_closed():
                        continue

                    if trade.is_closing():
                        continue

                    if not self.instrument.tradeable:
                        continue

                    if trade.is_dirty:
                        # entry quantity changed need to update the exits orders
                        trade.update_dirty(trader, self.instrument)

                    # potential order exec close price
                    close_exec_price = self.instrument.close_exec_price(trade.direction)

                    if (trade.tp > 0) and ((trade.direction > 0 and close_exec_price >= trade.tp) or (trade.direction < 0 and close_exec_price <= trade.tp)) and not trade.has_limit_order():
                        # close in profit at market (taker fee)
                        if trade.close(trader, self.instrument) > 0:
                            trade.exit_reason = trade.REASON_TAKE_PROFIT_MARKET

                    elif (trade.sl > 0) and ((trade.direction > 0 and close_exec_price <= trade.sl) or (trade.direction < 0 and close_exec_price >= trade.sl)) and not trade.has_stop_order():
                        # close a long or a short position at stop-loss level at market (taker fee)
                        if trade.close(trader, self.instrument) > 0:
                            trade.exit_reason = trade.REASON_STOP_LOSS_MARKET

        #
        # remove terminated, rejected, canceled and empty trades
        #

        mutated = False

        with self._trade_mutex:
            for trade in self.trades:
                if trade.can_delete():
                    mutated = True

                    # cleanup if necessary before deleting the trade related refs
                    trade.remove(trader, self.instrument)

                    # record the trade for analysis and study
                    if not trade.is_canceled():
                        # last update of stats before logging
                        trade.update_stats(self.instrument.close_exec_price(trade.direction), timestamp)

                        # realized profit/loss
                        profit_loss = trade.profit_loss - trade.entry_fees_rate() - trade.exit_fees_rate()

                        # perf sommed here it means that its not done during partial closing
                        if profit_loss != 0.0:
                            self._stats['perf'] += profit_loss
                            self._stats['best'] = max(self._stats['best'], profit_loss)
                            self._stats['worst'] = min(self._stats['worst'], profit_loss)

                        if profit_loss <= 0.0:
                            self._stats['cont-loss'] += 1
                            self._stats['cont-win'] = 1

                        elif profit_loss > 0.0:
                            self._stats['cont-loss'] = 0
                            self._stats['cont-win'] += 1

                        record = {
                            'id': trade.id,
                            'eot': trade.entry_open_time,
                            'xot': trade.exit_open_time,
                            'freot': trade.first_realized_entry_time,
                            'frxot': trade.first_realized_exit_time,
                            'lreot': trade.last_realized_entry_time,
                            'lrxot': trade.last_realized_exit_time,
                            'd': trade.direction_to_str(),
                            'l': self.instrument.format_price(trade.order_price),
                            'q': self.instrument.format_quantity(trade.order_quantity),
                            'e': self.instrument.format_quantity(trade.exec_entry_qty),
                            'x': self.instrument.format_quantity(trade.exec_exit_qty),
                            'tp': self.instrument.format_price(trade.take_profit),
                            'sl': self.instrument.format_price(trade.stop_loss),
                            'tf': timeframe_to_str(trade.timeframe),
                            'aep': self.instrument.format_price(trade.entry_price),
                            'axp': self.instrument.format_price(trade.exit_price),
                            's': trade.state_to_str(),
                            'b': self.instrument.format_price(trade.best_price()),
                            'w': self.instrument.format_price(trade.worst_price()),
                            'bt': trade.best_price_timestamp(),
                            'wt': trade.worst_price_timestamp(),
                            'pl': profit_loss,
                            'fees': trade.entry_fees_rate() + trade.exit_fees_rate(),
                            'c': trade.get_conditions(),
                            'label': trade.label,
                            'rpnl': self.instrument.format_price(trade.unrealized_profit_loss),  # once close its realized
                            'pnlcur': trade.profit_loss_currency
                        }

                        if profit_loss < 0:
                            self._stats['failed'].append(record)
                        elif profit_loss > 0:
                            self._stats['success'].append(record)
                        else:
                            self._stats['roe'].append(record)

                        if self._reporting == StrategyTrader.REPORTING_VERBOSE:
                            try:
                                self.report(trade, False)
                            except Exception as e:
                                error_logger.error(str(e))

                        # notify
                        if not trade.exit_reason:
                            if trade.exit_price >= trade.take_profit and trade.take_profit > 0:
                                trade.exit_reason = trade.REASON_TAKE_PROFIT_LIMIT
                            elif trade.exit_price <= trade.stop_loss and trade.stop_loss > 0:
                                trade.exit_reason = trade.REASON_STOP_LOSS_MARKET                    

                        trade.pl = profit_loss

                        self.notify_trade_exit(timestamp, trade)
                    else:
                        if not trade.exit_reason:
                            trade.exit_reason = trade.REASON_CANCELED_TIMEOUT

                        self.notify_trade_exit(timestamp, trade)

            # recreate the list of trades
            if mutated:
                trades_list = []

                for trade in self.trades:
                    if not trade.can_delete():
                        # keep only active and pending trades
                        trades_list.append(trade)

                self.trades = trades_list
コード例 #5
0
    def update_trades(self, timestamp):
        """
        Update managed trades per instruments and delete terminated trades.
        """
        if not self.trades:
            return

        trader = self.strategy.trader()

        #
        # for each trade check if the TP or SL is reached and trigger if necessary
        #

        self.lock()

        for trade in self.trades:

            #
            # managed operation
            #

            if trade.has_operations():
                mutated = False

                for operation in trade.operations:
                    mutated |= operation.test_and_operate(
                        trade, self.instrument, trader)

                if mutated:
                    trade.cleanup_operations()

            #
            # active trade
            #

            if trade.is_active():
                # for statistics usage
                trade.update_stats(
                    self.instrument.close_exec_price(trade.direction),
                    timestamp)

            #
            # asset trade
            #

            if trade.trade_type == StrategyTrade.TRADE_BUY_SELL:
                if trade.is_closed():
                    continue

                # process only on active trades
                if not trade.is_active():
                    # @todo timeout if not filled before condition...
                    continue

                if trade.is_closing():
                    continue

                if not self.instrument.tradeable:
                    continue

                # potential order exec close price (always close a long)
                close_exec_price = self.instrument.close_exec_price(Order.LONG)

                if trade.tp > 0 and (close_exec_price >= trade.tp):
                    # take profit order
                    # trade.modify_take_profit(trader, market, take_profit)

                    # close at market (taker fee)
                    if trade.close(trader, self.instrument.market_id):
                        # only get it at the last moment
                        market = trader.market(self.instrument.market_id)

                        # estimed profit/loss rate
                        profit_loss_rate = (
                            close_exec_price -
                            trade.entry_price) / trade.entry_price

                        # estimed maker/taker fee rate for entry and exit
                        if trade.get_stats()['entry-maker']:
                            profit_loss_rate -= market.maker_fee
                        else:
                            profit_loss_rate -= market.taker_fee

                        if trade.get_stats()['exit-maker']:
                            profit_loss_rate -= market.maker_fee
                        else:
                            profit_loss_rate -= market.taker_fee

                        # notify
                        self.strategy.notify_order(
                            trade.id, Order.SHORT, self.instrument.market_id,
                            market.format_price(close_exec_price), timestamp,
                            trade.timeframe, 'take-profit', profit_loss_rate)

                        # streaming (but must be done with notify)
                        self._global_streamer.member('buy-exit').update(
                            close_exec_price, timestamp)

                elif trade.sl > 0 and (close_exec_price <= trade.sl):
                    # stop loss order

                    # close at market (taker fee)
                    if trade.close(trader, self.instrument.market_id):
                        # only get it at the last moment
                        market = trader.market(self.instrument.market_id)

                        # estimed profit/loss rate
                        profit_loss_rate = (
                            close_exec_price -
                            trade.entry_price) / trade.entry_price

                        # estimed maker/taker fee rate for entry and exit
                        if trade.get_stats()['entry-maker']:
                            profit_loss_rate -= market.maker_fee
                        else:
                            profit_loss_rate -= market.taker_fee

                        if trade.get_stats()['exit-maker']:
                            profit_loss_rate -= market.maker_fee
                        else:
                            profit_loss_rate -= market.taker_fee

                        # notify
                        self.strategy.notify_order(
                            trade.id, Order.SHORT, self.instrument.market_id,
                            market.format_price(close_exec_price), timestamp,
                            trade.timeframe, 'stop-loss', profit_loss_rate)

                        # streaming (but must be done with notify)
                        self._global_streamer.member('buy-exit').update(
                            close_exec_price, timestamp)

            #
            # margin trade
            #

            elif trade.trade_type == StrategyTrade.TRADE_MARGIN or trade.trade_type == StrategyTrade.TRADE_IND_MARGIN:
                # process only on active trades
                if not trade.is_active():
                    # @todo timeout if not filled before condition...
                    continue

                if trade.is_closed():
                    continue

                if trade.is_closing():
                    continue

                if not self.instrument.tradeable:
                    continue

                # potential order exec close price
                close_exec_price = self.instrument.close_exec_price(
                    trade.direction)

                if (trade.tp > 0) and (trade.direction > 0
                                       and close_exec_price >= trade.tp) or (
                                           trade.direction < 0
                                           and close_exec_price <= trade.tp):
                    # close in profit at market (taker fee)
                    if trade.close(trader, self.instrument.market_id):
                        # only get it at the last moment
                        market = trader.market(self.instrument.market_id)

                        # estimed profit/loss rate
                        if trade.direction > 0 and trade.entry_price:
                            profit_loss_rate = (
                                close_exec_price -
                                trade.entry_price) / trade.entry_price
                        elif trade.direction < 0 and trade.entry_price:
                            profit_loss_rate = (
                                trade.entry_price -
                                close_exec_price) / trade.entry_price
                        else:
                            profit_loss_rate = 0

                        # estimed maker/taker fee rate for entry and exit
                        if trade.get_stats()['entry-maker']:
                            profit_loss_rate -= market.maker_fee
                        else:
                            profit_loss_rate -= market.taker_fee

                        if trade.get_stats()['exit-maker']:
                            profit_loss_rate -= market.maker_fee
                        else:
                            profit_loss_rate -= market.taker_fee

                        # and notify
                        self.strategy.notify_order(
                            trade.id, trade.close_direction(),
                            self.instrument.market_id,
                            market.format_price(close_exec_price), timestamp,
                            trade.timeframe, 'take-profit', profit_loss_rate)

                        # and for streaming
                        self._global_streamer.member(
                            'sell-exit' if trade.direction < 0 else 'buy-exit'
                        ).update(close_exec_price, timestamp)

                elif (trade.sl > 0) and (trade.direction > 0
                                         and close_exec_price <= trade.sl) or (
                                             trade.direction < 0
                                             and close_exec_price >= trade.sl):
                    # close a long or a short position at stop-loss level at market (taker fee)
                    if trade.close(trader, self.instrument.market_id):
                        # only get it at the last moment
                        market = trader.market(self.instrument.market_id)

                        # estimed profit/loss rate
                        if trade.direction > 0 and trade.entry_price:
                            profit_loss_rate = (
                                close_exec_price -
                                trade.entry_price) / trade.entry_price
                        elif trade.direction < 0 and trade.entry_price:
                            profit_loss_rate = (
                                trade.entry_price -
                                close_exec_price) / trade.entry_price
                        else:
                            profit_loss_rate = 0

                        # estimed maker/taker fee rate for entry and exit
                        if trade.get_stats()['entry-maker']:
                            profit_loss_rate -= market.maker_fee
                        else:
                            profit_loss_rate -= market.taker_fee

                        if trade.get_stats()['exit-maker']:
                            profit_loss_rate -= market.maker_fee
                        else:
                            profit_loss_rate -= market.taker_fee

                        # and notify
                        self.strategy.notify_order(
                            trade.id, trade.close_direction(),
                            self.instrument.market_id,
                            market.format_price(close_exec_price), timestamp,
                            trade.timeframe, 'stop-loss', profit_loss_rate)

                        # and for streaming
                        self._global_streamer.member(
                            'sell-exit' if trade.direction < 0 else 'buy-exit'
                        ).update(close_exec_price, timestamp)

        self.unlock()

        #
        # remove terminated, rejected, canceled and empty trades
        #

        mutated = False

        self.lock()

        for trade in self.trades:
            if trade.can_delete():
                mutated = True

                # cleanup if necessary before deleting the trade related refs, and add them to the deletion list
                trade.remove(trader)

                # record the trade for analysis and learning
                if not trade.is_canceled():
                    # @todo all this part could be in an async method of another background service, because
                    # it is not part of the trade managemnt neither strategy computing, its purely for reporting
                    # and view then we could add a list of the deleted trade (producer) and having another service (consumer) doing the rest

                    # estimation on mid last price, but might be close market price
                    market = trader.market(self.instrument.market_id)

                    # rate = (trade.best_price() - trade.entry_price) / trade.entry_price  # for best missed profit
                    rate = trade.profit_loss  # realized profit/loss

                    # fee rate for entry and exit
                    if trade._stats['entry-maker']:
                        rate -= market.maker_fee
                    else:
                        rate -= market.taker_fee

                    if trade._stats['exit-maker']:
                        rate -= market.maker_fee
                    else:
                        rate -= market.taker_fee

                    # estimed commission fee rate (futur, stocks)
                    # @todo

                    # perf sommed here it means that its not done during partial closing
                    if rate != 0.0:
                        self._stats['perf'] += rate
                        self._stats['worst'] = min(self._stats['worst'], rate)
                        self._stats['best'] = max(self._stats['best'], rate)

                    if rate <= 0.0:
                        self._stats['cont-loss'] += 1
                        self._stats['cont-win'] = 1

                    elif rate > 0.0:
                        self._stats['cont-loss'] = 0
                        self._stats['cont-win'] += 1

                    record = {
                        'id': trade.id,
                        'ts': trade.entry_open_time,
                        'd': trade.direction_to_str(),
                        'p': market.format_price(trade.entry_price),
                        'q': market.format_quantity(trade.order_quantity),
                        'e': market.format_quantity(trade.exec_entry_qty),
                        'x': market.format_quantity(trade.exec_exit_qty),
                        'tp': market.format_price(trade.take_profit),
                        'sl': market.format_price(trade.stop_loss),
                        'tf': timeframe_to_str(trade.timeframe),
                        'aep': market.format_price(trade.entry_price),
                        'axp': market.format_price(trade.exit_price),
                        's': trade.state_to_str(),
                        'b': market.format_price(trade.best_price()),
                        'w': market.format_price(trade.worst_price()),
                        'bt': trade.best_price_timestamp(),
                        'wt': trade.worst_price_timestamp(),
                        'rate': rate,
                        'c': trade.get_conditions()
                    }

                    if rate < 0:
                        self._stats['failed'].append(record)
                    elif rate > 0:
                        self._stats['success'].append(record)
                    else:
                        self._stats['roe'].append(record)

        # recreate the list of trades
        if mutated:
            trades_list = []

            for trade in self.trades:
                if not trade.can_delete():
                    # keep only active and pending trades
                    trades_list.append(trade)

            self.trades = trades_list

        self.unlock()
コード例 #6
0
    def update(self):
        count = 0

        while self._signals:
            signal = self._signals.popleft()

            label = ""
            message = ""
            icon = "contact-new"
            now = time.time()
            audio_alert = None

            if signal.signal_type == Signal.SIGNAL_SOCIAL_ENTER:
                # here we only assume that because of what 1broker return to us but should be timestamp in the model
                entry_date = signal.data.entry_date + timedelta(hours=2)
                position_timestamp = time.mktime(entry_date.timetuple())
                audio_alert = DesktopNotifier.AUDIO_ALERT_SIMPLE

                if now - position_timestamp > 120 * 60:
                    continue

                label = "Entry position on %s" % (signal.data.symbol, )
                message = "Trader %s enter %s on %s at %s (x%s)" % (
                    signal.data.author.name if signal.data.author is not None
                    else "???", "long" if signal.data.direction
                    == Position.LONG else "short", signal.data.symbol,
                    signal.data.entry_price, signal.data.leverage)

            elif signal.signal_type == Signal.SIGNAL_SOCIAL_EXIT:
                # here we only assume that because of what 1broker return to us but should be timestamp in the model
                exit_date = signal.data.exit_date + timedelta(hours=2)
                position_timestamp = time.mktime(exit_date.timetuple())
                audio_alert = DesktopNotifier.AUDIO_ALERT_SIMPLE

                if now - position_timestamp > 120 * 60:
                    continue

                label = "Exit position on %s" % (signal.data.symbol, )
                message = "Trader %s exit %s on %s at %s" % (
                    signal.data.author.name, "long"
                    if signal.data.direction == Position.LONG else "short",
                    signal.data.symbol, signal.data.exit_price)

            # # @todo a threshold... or a timelimit
            # elif signal.signal_type == Signal.SIGNAL_TRADE_ALERT:
            #     icon = "go-down"
            #     label = "Position loss on %s" % (signal.data.symbol,)
            #     audio_alert = DesktopNotifier.AUDIO_ALERT_WARNING

            #     message = "Position %s %s of %s on %s start at %s %s is in regretable loss %s (%s%%) :$" % (
            #         signal.data.position_id,
            #         "long" if signal.data.direction == Position.LONG else "short",
            #         signal.data.author.name if signal.data.author is not None else "???",
            #         signal.data.trader.name,
            #         signal.data.entry_price,
            #         signal.data.symbol,
            #         signal.data.profit_loss,
            #         signal.data.profit_loss_rate * 100.0)

            # elif signal.signal_type == Signal.SIGNAL_TRADE_ENJOY:
            #     icon = "go-up"
            #     label = "Position profit on %s" % (signal.data.symbol,)
            #     audio_alert = DesktopNotifier.AUDIO_ALERT_SIMPLE

            #     message = "Position %s %s of %s on %s start at %s %s is in enjoyable profit %s (%s%%) :)" % (
            #         signal.data.position_id,
            #         "long" if signal.data.direction == Position.LONG else "short",
            #         signal.data.author.name if signal.data.author is not None else "???",
            #         signal.data.trader.name,
            #         signal.data.entry_price,
            #         signal.data.symbol,
            #         signal.data.profit_loss,
            #         signal.data.profit_loss_rate * 100.0)

            elif signal.signal_type == Signal.SIGNAL_STRATEGY_ENTRY_EXIT:
                # @todo in addition of entry/exit, modification and a reason of the exit/modification
                icon = "contact-new"
                direction = "long" if signal.data[
                    'direction'] == Position.LONG else "short"
                audio_alert = DesktopNotifier.AUDIO_ALERT_SIMPLE

                if signal.data['action'] == 'stop':
                    audio_alert = DesktopNotifier.AUDIO_ALERT_WARNING

                ldatetime = datetime.fromtimestamp(
                    signal.data['timestamp']).strftime('%Y-%m-%d %H:%M:%S')

                label = "Signal %s %s on %s" % (
                    signal.data['action'],
                    direction,
                    signal.data['symbol'],
                )

                message = "%s@%s (%s) %s %s at %s - #%s in %s" % (
                    signal.data['symbol'], signal.data['price'],
                    signal.data['trader-name'], signal.data['action'],
                    direction, ldatetime, signal.data['trade-id'],
                    timeframe_to_str(signal.data['timeframe']))

                if signal.data['stop-loss']:
                    message += " SL@%s" % (signal.data['stop-loss'], )

                if signal.data['take-profit']:
                    message += " TP@%s" % (signal.data['take-profit'], )

                if signal.data['rate'] is not None:
                    message += " (%.2f%%)" % ((signal.data['rate'] * 100), )

                if self.discord:
                    if signal.data['identifier'] in self._discord_webhook:
                        send_to_discord(
                            self._discord_webhook[signal.data['identifier']],
                            'CryptoBot', '```' + message + '```')
                    else:
                        send_to_discord(self._discord_webhook['signals'],
                                        'CryptoBot', '```' + message + '```')

                # log them to the signal view
                Terminal.inst().notice(message, view="signal")

            # process sound
            if not self.backtesting and self.audible and audio_alert:
                # if repeat
                for i in range(0, self._alerts[audio_alert[1]]):
                    subprocess.Popen([
                        'aplay', '-D', self._audio_device,
                        self._alerts[audio_alert[0]]
                    ],
                                     stdout=subprocess.DEVNULL,
                                     stderr=subprocess.DEVNULL)

                # duration = 1  # second
                # freq = 440  # Hz
                # os.system('play --no-show-progress --null --channels 1 synth %s sine %f' % (duration, freq))

            if not self.backtesting and self.popups and message:
                n = notify2.Notification(label, message, icon)

                n.show()

            count += 1
            if count > 10:
                # no more than per loop
                break
コード例 #7
0
ファイル: strategytrade.py プロジェクト: stockec/siis
 def timeframe_to_str(self):
     return timeframe_to_str(self._timeframe)
コード例 #8
0
 def timeframe_to_str(self):
     if self._timeframe > 0:
         return timeframe_to_str(self._timeframe)
     else:
         return "any"
コード例 #9
0
    def process_signal(self, signal):
        label = ""
        message = ""
        icon = "contact-new"
        now = time.time()
        alert = None

        if Signal.SIGNAL_STRATEGY_SIGNAL_ENTRY <= signal.signal_type <= Signal.SIGNAL_STRATEGY_TRADE_UPDATE:
            icon = "contact-new"
            direction = "long" if signal.data[
                'direction'] == Position.LONG else "short"
            alert = DesktopNotifier.AUDIO_ALERT_SIGNAL_NEW

            if signal.data['way'] == "exit" and 'profit-loss' in signal.data:
                if signal.data['profit-loss'] < 0.0:
                    alert = DesktopNotifier.AUDIO_ALERT_TRADE_LOST
                    icon = self._alerts[alert][2]
                else:
                    alert = DesktopNotifier.AUDIO_ALERT_TRADE_WIN
                    icon = self._alerts[alert][2]

            ldatetime = datetime.fromtimestamp(
                signal.data['timestamp']).strftime('%Y-%m-%d %H:%M:%S')

            # generic signal reason
            action = signal.data['way']

            # specified exit reason
            if action == "exit" and 'stats' in signal.data and 'exit-reason' in signal.data[
                    'stats']:
                action = signal.data['stats']['exit-reason']

            label = "Signal %s %s on %s" % (
                action,
                direction,
                signal.data['symbol'],
            )

            way = '>' if signal.data['way'] == "entry" else '<'
            exit_reason = signal.data['stats'].get(
                'exit-reason', "") if 'stats' in signal.data else ""

            message = "%s@%s (%s) %s %s at %s - #%s in %s" % (
                signal.data['symbol'], signal.data['order-price'],
                signal.data['app-name'], action, direction, ldatetime,
                signal.data['id'], timeframe_to_str(signal.data['timeframe']))

            if signal.data.get('stop-loss-price'):
                message += " SL@%s" % (signal.data['stop-loss-price'], )

            if signal.data.get('take-profit-price'):
                message += " TP@%s" % (signal.data['take-profit-price'], )

            if signal.data.get('profit-loss') is not None:
                message += " (%.2f%%)" % ((signal.data['profit-loss'] * 100), )

            if signal.data['comment'] is not None:
                message += " (%s)" % signal.data['comment']

            # and in signal logger (@todo to be moved)
            # signal_logger.info(message)

        # process sound
        if not self._backtesting and self._audible and alert is not None:
            self.play_audio_alert(alert)

        if not self._backtesting and self._popups and message:
            if self.notify2:
                n = self.notify2.Notification(label, message, icon)
                n.show()

        elif signal.signal_type == Signal.SIGNAL_MARKET_SIGNAL:
            return

        elif signal.signal_type == Signal.SIGNAL_WATCHDOG_TIMEOUT:
            return

        elif signal.signal_type == Signal.SIGNAL_WATCHDOG_UNREACHABLE:
            return
コード例 #10
0
 def dumps_notify(self, timestamp, strategy_trader):
     """
     Dumps to dict for notify/history, same format as for StrategyTrade.
     """
     if self.signal == StrategySignal.SIGNAL_EXIT:
         return {
             'version':
             self.version(),
             'trade':
             "signal",
             'id':
             -1,
             'app-name':
             strategy_trader.strategy.name,
             'app-id':
             strategy_trader.strategy.identifier,
             'timestamp':
             timestamp,
             'symbol':
             strategy_trader.instrument.market_id,
             'way':
             "entry",
             'entry-timeout':
             timeframe_to_str(self.entry_timeout),
             'expiry':
             self.expiry,
             'timeframe':
             timeframe_to_str(self.timeframe),
             'is-user-trade':
             False,
             'comment':
             self._comment,
             'direction':
             self.direction_to_str(),
             'order-price':
             strategy_trader.instrument.format_price(self.p),
             'stop-loss-price':
             strategy_trader.instrument.format_price(self.sl),
             'take-profit-price':
             strategy_trader.instrument.format_price(self.tp),
             'entry-open-time':
             self.dump_timestamp(self.ts),
         }
     elif self.signal == StrategySignal.SIGNAL_EXIT:
         return {
             'version':
             self.version(),
             'trade':
             "signal",
             'id':
             -1,
             'app-name':
             strategy_trader.strategy.name,
             'app-id':
             strategy_trader.strategy.identifier,
             'timestamp':
             timestamp,
             'symbol':
             strategy_trader.instrument.market_id,
             'way':
             "exit",
             'entry-timeout':
             timeframe_to_str(self.entry_timeout),
             'expiry':
             self.expiry,
             'timeframe':
             timeframe_to_str(self.timeframe),
             'is-user-trade':
             False,
             'comment':
             self._comment,
             'direction':
             self.direction_to_str(),
             'take-profit-price':
             strategy_trader.instrument.format_price(self.tp),
             'stop-loss-price':
             strategy_trader.instrument.format_price(self.sl),
             'exit-open-time':
             self.dump_timestamp(self.ts),
         }
コード例 #11
0
ファイル: importer.py プロジェクト: venkiiee/siis
def do_importer(options):
    tool = Importer()

    Terminal.inst().info("Starting SIIS importer...")
    Terminal.inst().flush()

    # database manager
    Database.create(options)
    Database.inst().setup(options)

    # want speedup the database inserts
    Database.inst().enable_fetch_mode()

    filename = options.get('filename')
    detected_format = FORMAT_UNDEFINED
    detected_timeframe = None
    is_mtx_tick = False

    pathname = pathlib.Path(filename)
    if not pathname.exists():
        error_exit(None, "File %s does not exists" % pathname.name)

    timeframe = None

    if not options.get('timeframe'):
        timeframe = None
    else:
        if options['timeframe'] in TIMEFRAME_FROM_STR_MAP:
            timeframe = TIMEFRAME_FROM_STR_MAP[options['timeframe']]
        else:
            try:
                timeframe = int(options['timeframe'])
            except:
                pass

    src = open(filename, "rt")

    if filename.endswith(".siis"):
        detected_format = FORMAT_SIIS
    elif filename.endswith(".csv"):
        # detect the format from the first row
        row = src.readline().rstrip('\n')
        if row.count('\t') > 0:
            if row.count(
                    '\t'
            ) == 5 and row == "<DATE>\t<TIME>\t<BID>\t<ASK>\t<LAST>\t<VOLUME>":
                detected_format = FORMAT_MT5
                detected_timeframe = Instrument.TF_TICK
                is_mtx_tick = True

            elif row.count(
                    '\t'
            ) == 8 and row == "<DATE>\t<TIME>\t<OPEN>\t<HIGH>\t<LOW>\t<CLOSE>\t<TICKVOL>\t<VOL>\t<SPREAD>":
                detected_format = FORMAT_MT5
                is_mtx_tick = False

                # from filename try to detect the timeframe
                parts = pathname.name.split('_')
                if len(parts) >= 2:
                    detected_timeframe = MT5_TIMEFRAMES.get(parts[1])

            # ignore the header line
        elif row.count(',') > 0:
            if row.count(',') == 4:
                detected_format = FORMAT_MT4
                detected_timeframe = Instrument.TF_TICK
                is_mtx_tick = True

            elif row.count(',') == 6:
                detected_format = FORMAT_MT4
                is_mtx_tick = False

                # from filename try to detect the timeframe
                parts = pathname.name.split('.')
                if len(parts) > 0:
                    for mt_tf, tf in MT4_TIMEFRAMES.items():
                        if parts[0].endswith(mt_tf):
                            detected_timeframe = tf
                            break

            # reset because first row is data
            src.seek(0, 0)

    if detected_format == FORMAT_UNDEFINED:
        error_exit(src, "Unknown file format")

    if detected_format in (FORMAT_MT4, FORMAT_MT5):
        if detected_timeframe is not None and timeframe is None:
            Terminal.inst().message("Auto-detected timeframe %s" %
                                    timeframe_to_str(detected_timeframe))

        if detected_timeframe and timeframe and detected_timeframe != timeframe:
            error_exit(
                src,
                "Auto-detected timeframe %s is different of specified timeframe %s"
                % (timeframe_to_str(detected_timeframe),
                   timeframe_to_str(timeframe)))

    market_id = ""
    broker_id = ""

    # UTC option dates
    from_date = options.get('from')
    to_date = options.get('to')

    if detected_format == FORMAT_SIIS:
        # first row gives format details
        header = src.readline()

        if not header.startswith("format=SIIS\t"):
            error_exit(src, "Unsupported file format")

        info = header.split('\t')

        for nfo in info:
            k, v = nfo.split('=')

            if k == "version":
                if v != "1.0.0":
                    error_exit(src, "Unsupported format version")
            elif k == "created":
                pass  # informational only
            elif k == "broker":
                broker_id = v
            elif k == "market":
                market_id = v
            elif k == "from":
                pass  # informational only
            elif k == "to":
                pass  # informational only
            elif k == "timeframe":
                if v != "any":
                    timeframe = timeframe_from_str(v)
                else:
                    timeframe = None
    else:
        # need broker, market and timeframe
        broker_id = options.get('broker')
        market_id = options.get('market')

        if not broker_id:
            error_exit(src, "Missing target broker identifier")

        if not market_id or ',' in market_id:
            error_exit(src, "Missing or invalid target market identifier")

        if timeframe is None:
            if is_mtx_tick:
                timeframe = Instrument.TF_TICK
            elif detected_timeframe:
                timeframe = detected_timeframe
            else:
                error_exit(src, "Missing target timeframe")

    # limited sub-range
    from_date_str = from_date.strftime(
        "%Y-%m-%dT%H:%M:%SZ") if from_date else None
    to_date_str = to_date.strftime("%Y-%m-%dT%H:%M:%SZ") if to_date else None

    total_count = 0

    try:
        if detected_format == FORMAT_SIIS:
            cur_timeframe = None
            cur_from_date = from_date
            cur_to_date = to_date

            while 1:
                row = src.readline()
                if not row:
                    break

                row = row.rstrip("\n")
                if row.startswith("timeframe="):
                    # specify the timeframe of the next rows
                    k, v = row.split('=')
                    cur_timeframe = timeframe_from_str(v)
                    continue

                if cur_timeframe is None:
                    # need a specified timeframe
                    continue

                if cur_timeframe == Instrument.TF_TICK:
                    total_count += import_tick_siis_1_0_0(
                        broker_id, market_id, cur_from_date, cur_to_date, row)

                elif cur_timeframe > 0:
                    total_count += import_ohlc_siis_1_0_0(
                        broker_id, market_id, cur_timeframe, cur_from_date,
                        cur_to_date, row)

        elif detected_format == FORMAT_MT4:
            cur_timeframe = timeframe if not is_mtx_tick else Instrument.TF_TICK
            cur_from_date = from_date
            cur_to_date = to_date

            if cur_timeframe == Instrument.TF_TICK:
                while 1:
                    row = src.readline()
                    if not row:
                        break

                    row = row.rstrip("\n")
                    total_count += import_tick_mt4(tool, broker_id, market_id,
                                                   cur_from_date, cur_to_date,
                                                   row)

            elif cur_timeframe > 0:
                while 1:
                    row = src.readline()
                    if not row:
                        break

                    row = row.rstrip("\n")
                    total_count += import_ohlc_mt4(broker_id, market_id,
                                                   cur_timeframe,
                                                   cur_from_date, cur_to_date,
                                                   row)

        elif detected_format == FORMAT_MT5:
            cur_timeframe = timeframe if not is_mtx_tick else Instrument.TF_TICK
            cur_from_date = from_date
            cur_to_date = to_date

            if cur_timeframe == Instrument.TF_TICK:
                while 1:
                    row = src.readline()
                    if not row:
                        break

                    row = row.rstrip("\n")
                    total_count += import_tick_mt5(tool, broker_id, market_id,
                                                   cur_from_date, cur_to_date,
                                                   row)

            elif cur_timeframe > 0:
                while 1:
                    row = src.readline()
                    if not row:
                        break

                    row = row.rstrip("\n")
                    total_count += import_ohlc_mt5(broker_id, market_id,
                                                   cur_timeframe,
                                                   cur_from_date, cur_to_date,
                                                   row)

    except Exception as e:
        error_logger.error(str(e))
    finally:
        src.close()
        src = None

    Terminal.inst().info("Imported %s samples" % (total_count))

    Terminal.inst().info("Flushing database...")
    Terminal.inst().flush()

    Database.terminate()

    Terminal.inst().info("Importation done!")
    Terminal.inst().flush()

    Terminal.terminate()
    sys.exit(0)
コード例 #12
0
ファイル: rebuilder.py プロジェクト: venkiiee/siis
def do_rebuilder(options):
    Terminal.inst().info("Starting SIIS rebuilder using %s identity..." %
                         options['identity'])
    Terminal.inst().flush()

    # database manager
    Database.create(options)
    Database.inst().setup(options)

    # want speedup the database inserts
    Database.inst().enable_fetch_mode()

    timeframe = -1
    cascaded = None

    if not options.get('timeframe'):
        timeframe = 60  # default to 1min
    else:
        if options['timeframe'] in TIMEFRAME_FROM_STR_MAP:
            timeframe = TIMEFRAME_FROM_STR_MAP[options['timeframe']]
        else:
            try:
                timeframe = int(options['timeframe'])
            except:
                pass

    if not options.get('cascaded'):
        cascaded = None
    else:
        if options['cascaded'] in TIMEFRAME_FROM_STR_MAP:
            cascaded = TIMEFRAME_FROM_STR_MAP[options['cascaded']]
        else:
            try:
                cascaded = int(options['cascaded'])
            except:
                pass

    if timeframe < 0:
        error_logger.error("Invalid timeframe")
        sys.exit(-1)

    from_date = options.get('from')
    to_date = options.get('to')

    if not to_date:
        today = datetime.now().astimezone(UTC())

        if timeframe == Instrument.TF_MONTH:
            to_date = today + timedelta(months=1)
        else:
            to_date = today + timedelta(seconds=timeframe)

        to_date = to_date.replace(microsecond=0)

    if timeframe > 0 and timeframe not in GENERATED_TF:
        logger.error("Timeframe %s is not allowed !" %
                     timeframe_to_str(timeframe))
        sys.exit(-1)

    for market in options['market'].split(','):
        if market.startswith('!') or market.startswith('*'):
            continue

        timestamp = from_date.timestamp()
        to_timestamp = to_date.timestamp()

        progression = 0.0
        prev_update = timestamp
        count = 0
        total_count = 0

        progression_incr = (to_timestamp - timestamp) * 0.01

        tts = 0.0
        prev_tts = 0.0

        generators = []
        from_tf = timeframe

        last_ticks = []
        last_ohlcs = {}

        if timeframe == Instrument.TF_TICK:
            tick_streamer = Database.inst().create_tick_streamer(
                options['broker'],
                market,
                from_date=from_date,
                to_date=to_date)
        else:
            ohlc_streamer = Database.inst().create_ohlc_streamer(
                options['broker'],
                market,
                timeframe,
                from_date=from_date,
                to_date=to_date)

        # cascaded generation of candles
        if cascaded:
            for tf in GENERATED_TF:
                if tf > timeframe:
                    # from timeframe greater than initial
                    if tf <= cascaded:
                        # until max cascaded timeframe
                        generators.append(CandleGenerator(from_tf, tf))
                        from_tf = tf

                        # store for generation
                        last_ohlcs[tf] = []
                else:
                    from_tf = tf

        if options.get('target'):
            target = TIMEFRAME_FROM_STR_MAP.get(options.get('target'))

            if target % timeframe != 0:
                logger.error(
                    "Timeframe %s is not a multiple of %s !" %
                    (timeframe_to_str(target), timeframe_to_str(timeframe)))
                sys.exit(-1)

            generators.append(CandleGenerator(timeframe, target))

            # store for generation
            last_ohlcs[target] = []

        if timeframe > 0:
            last_ohlcs[timeframe] = []

        if timeframe == 0:
            while not tick_streamer.finished():
                ticks = tick_streamer.next(timestamp + Instrument.TF_1M)

                count = len(ticks)
                total_count += len(ticks)

                for data in ticks:
                    if data[0] > to_timestamp:
                        break

                    if generators:
                        last_ticks.append(data)

                # generate higher candles
                for generator in generators:
                    if generator.from_tf == 0:
                        candles = generator.generate_from_ticks(last_ticks)

                        if candles:
                            for c in candles:
                                store_ohlc(options['broker'], market,
                                           generator.to_tf, c)

                            last_ohlcs[generator.to_tf] += candles

                        # remove consumed ticks
                        last_ticks = []
                    else:
                        candles = generator.generate_from_candles(
                            last_ohlcs[generator.from_tf])

                        if candles:
                            for c in candles:
                                store_ohlc(options['broker'], market,
                                           generator.to_tf, c)

                            last_ohlcs[generator.to_tf] += candles

                        # remove consumed candles
                        last_ohlcs[generator.from_tf] = []

                if timestamp - prev_update >= progression_incr:
                    progression += 1

                    Terminal.inst().info(
                        "%i%% on %s, %s ticks/trades for 1 minute, current total of %s..."
                        % (progression, format_datetime(timestamp), count,
                           total_count))

                    prev_update = timestamp
                    count = 0

                if timestamp > to_timestamp:
                    break

                timestamp += Instrument.TF_1M  # by step of 1m

                # calm down the storage of tick, if parsing is faster
                while Database.inst().num_pending_ticks_storage(
                ) > TICK_STORAGE_DELAY:
                    time.sleep(
                        TICK_STORAGE_DELAY)  # wait a little before continue

            if progression < 100:
                Terminal.inst().info(
                    "100%% on %s, %s ticks/trades for 1 minute, current total of %s..."
                    % (format_datetime(timestamp), count, total_count))

        elif timeframe > 0:
            while not ohlc_streamer.finished():
                ohlcs = ohlc_streamer.next(timestamp +
                                           timeframe * 100)  # per 100

                count = len(ohlcs)
                total_count += len(ohlcs)

                for data in ohlcs:
                    if data.timestamp > to_timestamp:
                        break

                    if generators:
                        last_ohlcs[timeframe].append(data)

                    tts = data.timestamp

                    if not prev_tts:
                        prev_tts = tts

                    prev_tts = tts
                    timestamp = tts

                # generate higher candles
                for generator in generators:
                    candles = generator.generate_from_candles(
                        last_ohlcs[generator.from_tf])
                    if candles:
                        for c in candles:
                            store_ohlc(options['broker'], market,
                                       generator.to_tf, c)

                        last_ohlcs[generator.to_tf].extend(candles)

                    # remove consumed candles
                    last_ohlcs[generator.from_tf] = []

                if timestamp - prev_update >= progression_incr:
                    progression += 1

                    Terminal.inst().info(
                        "%i%% on %s, %s ohlcs for 1 minute, current total of %s..."
                        % (progression, format_datetime(timestamp), count,
                           total_count))

                    prev_update = timestamp
                    count = 0

                if timestamp > to_timestamp:
                    break

                if count == 0:
                    timestamp += timeframe * 100

            if progression < 100:
                Terminal.inst().info(
                    "100%% on %s, %s ohlcs for 1 minute, current total of %s..."
                    % (format_datetime(timestamp), count, total_count))

    Terminal.inst().info("Flushing database...")
    Terminal.inst().flush()

    Database.terminate()

    Terminal.inst().info("Rebuild done!")
    Terminal.inst().flush()

    Terminal.terminate()
    sys.exit(0)
コード例 #13
0
 def dumps_notify_exit(self, timestamp, strategy_trader):
     """
     Dumps to dict for notify/history.
     """
     return {
         'version': self.version(),
         'trade': self.trade_type_to_str(),
         'id': self.id,
         'app-name': strategy_trader.strategy.name,
         'app-id': strategy_trader.strategy.identifier,
         'timestamp': timestamp,
         'symbol': strategy_trader.instrument.market_id,
         'way': "exit",
         'entry-timeout': timeframe_to_str(self._entry_timeout),
         'expiry': self._expiry,
         'timeframe': timeframe_to_str(self._timeframe),
         'is-user-trade': self._user_trade,
         'comment': self._comment,
         'direction': self.direction_to_str(),
         'order-price': strategy_trader.instrument.format_price(self.op),
         'order-qty': strategy_trader.instrument.format_quantity(self.oq),
         'stop-loss-price':
         strategy_trader.instrument.format_price(self.sl),
         'take-profit-price':
         strategy_trader.instrument.format_price(self.tp),
         'avg-entry-price':
         strategy_trader.instrument.format_price(self.aep),
         'avg-exit-price':
         strategy_trader.instrument.format_price(self.axp),
         'entry-open-time': self.dump_timestamp(self.eot),
         'exit-open-time': self.dump_timestamp(self.xot),
         'filled-entry-qty':
         strategy_trader.instrument.format_quantity(self.e),
         'filled-exit-qty':
         strategy_trader.instrument.format_quantity(self.x),
         'profit-loss-pct': round(self.pl * 100.0, 2),
         'num-exit-trades': len(self.exit_trades),
         'stats': {
             'best-price':
             strategy_trader.instrument.format_price(
                 self._stats['best-price']),
             'best-datetime':
             self.dump_timestamp(self._stats['best-timestamp']),
             'worst-price':
             strategy_trader.instrument.format_price(
                 self._stats['worst-price']),
             'worst-datetime':
             self.dump_timestamp(self._stats['worst-timestamp']),
             'entry-order-type':
             order_type_to_str(self._stats['entry-order-type']),
             'first-realized-entry-datetime':
             self.dump_timestamp(
                 self._stats['first-realized-entry-timestamp']),
             'first-realized-exit-datetime':
             self.dump_timestamp(
                 self._stats['first-realized-exit-timestamp']),
             'last-realized-entry-datetime':
             self.dump_timestamp(
                 self._stats['last-realized-entry-timestamp']),
             'last-realized-exit-datetime':
             self.dump_timestamp(
                 self._stats['last-realized-exit-timestamp']),
             'profit-loss-currency':
             self._stats['profit-loss-currency'],
             'profit-loss':
             self._stats['unrealized-profit-loss'],
             'entry-fees':
             self._stats['entry-fees'],
             'exit-fees':
             self._stats['exit-fees'],
             'exit-reason':
             StrategyTrade.reason_to_str(self._stats['exit-reason'])
         }
     }
コード例 #14
0
ファイル: optimizer.py プロジェクト: Johannesduvenage/siis
def do_optimizer(options):
    Terminal.inst().info("Starting SIIS optimizer...")
    Terminal.inst().flush()

    # database manager
    Database.create(options)
    Database.inst().setup(options)

    broker_id = options['broker']
    market_id = options['market']

    timeframe = None

    from_date = options.get('from')
    to_date = options.get('to')

    if not to_date:
        today = datetime.now().astimezone(UTC())

        if timeframe == Instrument.TF_MONTH:
            to_date = today + timedelta(months=1)
        else:
            to_date = today + timedelta(seconds=timeframe)

        to_date = to_date.replace(microsecond=0)

    if not options.get('timeframe'):
        timeframe = None
    else:
        if options['timeframe'] in TIMEFRAME_FROM_STR_MAP:
            timeframe = TIMEFRAME_FROM_STR_MAP[options['timeframe']]
        else:
            try:
                timeframe = int(options['timeframe'])
            except:
                pass

    try:
        # checking data integrity, gap...
        if timeframe is None:
            for market in options['market'].split(','):
                if market.startswith('!') or market.startswith('*'):
                    continue

                for tf in GENERATED_TF:
                    Terminal.inst().info("Verifying %s OHLC %s..." % (market, timeframe_to_str(tf)))

                    check_ohlcs(options['broker'], market, tf, from_date, to_date)

        elif timeframe == Instrument.TF_TICK:
            for market in options['market'].split(','):
                if market.startswith('!') or market.startswith('*'):
                    continue

                Terminal.inst().info("Verifying %s ticks/trades..." % (market,))

                check_ticks(options['broker'], market, from_date, to_date)

        elif timeframe > 0:
            # particular ohlc
            for market in options['market'].split(','):
                if market.startswith('!') or market.startswith('*'):
                    continue

                Terminal.inst().info("Verifying %s OHLC %s..." % (market, timeframe_to_str(timeframe)))

                check_ohlcs(options['broker'], market, timeframe, from_date, to_date)
    except KeyboardInterrupt:
        pass
    finally:
        pass

    Terminal.inst().info("Flushing database...")
    Terminal.inst().flush() 

    Database.terminate()

    Terminal.inst().info("Optimization done!")
    Terminal.inst().flush()

    Terminal.terminate()
    sys.exit(0)
コード例 #15
0
    def fetch_and_generate(self,
                           market_id,
                           timeframe,
                           from_date=None,
                           to_date=None,
                           n_last=1000,
                           fetch_option="",
                           cascaded=None):
        if timeframe > 0 and timeframe not in self.GENERATED_TF:
            logger.error("Timeframe %i is not allowed !" % (timeframe, ))
            return

        generators = []
        from_tf = timeframe

        self._last_ticks = []
        self._last_ohlcs = {}

        if not from_date and n_last:
            # compute a from date
            today = datetime.now().astimezone(UTC())

            if timeframe >= Instrument.TF_MONTH:
                from_date = (
                    today -
                    timedelta(months=int(timeframe / Instrument.TF_MONTH) *
                              n_last)).replace(day=1).replace(hour=0).replace(
                                  minute=0).replace(second=0)
            elif timeframe >= Instrument.TF_1D:
                from_date = (today - timedelta(
                    days=int(timeframe / Instrument.TF_1D) * n_last)).replace(
                        hour=0).replace(minute=0).replace(second=0)
            elif timeframe >= Instrument.TF_1H:
                from_date = (today - timedelta(
                    hours=int(timeframe / Instrument.TF_1H) * n_last)).replace(
                        minute=0).replace(second=0)
            elif timeframe >= Instrument.TF_1M:
                from_date = (
                    today -
                    timedelta(minutes=int(timeframe / Instrument.TF_1M) *
                              n_last)).replace(second=0)
            elif timeframe >= Instrument.TF_1S:
                from_date = (today - timedelta(
                    seconds=int(timeframe / Instrument.TF_1S) * n_last))

            from_date = from_date.replace(microsecond=0)

        if not to_date:
            today = datetime.now().astimezone(UTC())

            if timeframe == Instrument.TF_MONTH:
                to_date = today + timedelta(months=1)
            else:
                to_date = today + timedelta(seconds=timeframe)

            to_date = to_date.replace(microsecond=0)

        # cascaded generation of candles
        if cascaded:
            for tf in Fetcher.GENERATED_TF:
                if tf > timeframe:
                    # from timeframe greater than initial
                    if tf <= cascaded:
                        # until max cascaded timeframe
                        generators.append(CandleGenerator(from_tf, tf))
                        from_tf = tf

                        # store for generation
                        self._last_ohlcs[tf] = []
                else:
                    from_tf = tf

        if timeframe > 0:
            self._last_ohlcs[timeframe] = []

        n = 0
        t = 0

        if timeframe == 0:
            for data in self.fetch_trades(market_id, from_date, to_date, None):
                # store (int timestamp in ms, str bid, str ofr, str volume)
                Database.inst().store_market_trade(
                    (self.name, market_id, data[0], data[1], data[2], data[3]))

                if generators:
                    self._last_ticks.append(
                        (float(data[0]) * 0.001, float(data[1]),
                         float(data[2]), float(data[3])))

                # generate higher candles
                for generator in generators:
                    if generator.from_tf == 0:
                        candles = generator.generate_from_ticks(
                            self._last_ticks)

                        if candles:
                            for c in candles:
                                self.store_candle(market_id, generator.to_tf,
                                                  c)

                            self._last_ohlcs[generator.to_tf] += candles

                        # remove consumed ticks
                        self._last_ticks = []
                    else:
                        candles = generator.generate_from_candles(
                            self._last_ohlcs[generator.from_tf])

                        if candles:
                            for c in candles:
                                self.store_candle(market_id, generator.to_tf,
                                                  c)

                            self._last_ohlcs[generator.to_tf] += candles

                        # remove consumed candles
                        self._last_ohlcs[generator.from_tf] = []

                n += 1
                t += 1

                if n == 10000:
                    n = 0
                    Terminal.inst().info("%i trades for %s..." %
                                         (t, market_id))

                # calm down the storage of tick, if parsing is faster
                while Database.inst().num_pending_ticks_storage(
                ) > Fetcher.MAX_PENDING_TICK:
                    time.sleep(Fetcher.TICK_STORAGE_DELAY
                               )  # wait a little before continue

            logger.info("Fetched %i trades for %s" % (t, market_id))

        elif timeframe > 0:
            for data in self.fetch_candles(market_id, timeframe, from_date,
                                           to_date, None):
                # store (int timestamp ms, str open bid, high bid, low bid, close bid, open ofr, high ofr, low ofr, close ofr, volume)
                Database.inst().store_market_ohlc(
                    (self.name, market_id, data[0], int(timeframe), data[1],
                     data[2], data[3], data[4], data[5], data[6], data[7],
                     data[8], data[9]))

                if generators:
                    candle = Candle(float(data[0]) * 0.001, timeframe)

                    candle.set_bid_ohlc(float(data[1]), float(data[2]),
                                        float(data[3]), float(data[4]))
                    candle.set_ofr_ohlc(float(data[5]), float(data[6]),
                                        float(data[7]), float(data[8]))

                    candle.set_volume(float(data[9]))
                    candle.set_consolidated(True)

                    self._last_ohlcs[timeframe].append(candle)

                # generate higher candles
                for generator in generators:
                    candles = generator.generate_from_candles(
                        self._last_ohlcs[generator.from_tf])
                    if candles:
                        for c in candles:
                            self.store_candle(market_id, generator.to_tf, c)

                        self._last_ohlcs[generator.to_tf].extend(candles)

                    # remove consumed candles
                    self._last_ohlcs[generator.from_tf] = []

                n += 1
                t += 1

                if n == 1000:
                    n = 0
                    Terminal.inst().info(
                        "%i candles for %s in %s..." %
                        (t, market_id, timeframe_to_str(timeframe)))

            logger.info("Fetched %i candles for %s in %s" %
                        (t, market_id, timeframe_to_str(timeframe)))
コード例 #16
0
ファイル: strategytrader.py プロジェクト: simhaonline/siis
    def update_trades(self, timestamp):
        """
        Update managed trades per instruments and delete terminated trades.
        """
        if not self.trades:
            return

        trader = self.strategy.trader()

        #
        # for each trade check if the TP or SL is reached and trigger if necessary
        #

        self.lock()

        for trade in self.trades:

            #
            # managed operation
            #

            if trade.has_operations():
                mutated = False

                for operation in trade.operations:
                    mutated |= operation.test_and_operate(trade, self.instrument, trader)

                if mutated:
                    trade.cleanup_operations()

            #
            # active trade
            #

            if trade.is_active():
                # for statistics usage
                trade.update_stats(self.instrument.close_exec_price(trade.direction), timestamp)

            #
            # asset trade
            #

            if trade.trade_type == StrategyTrade.TRADE_BUY_SELL:
                if trade.is_closed():
                    continue

                # process only on active trades
                if not trade.is_active():
                    # @todo timeout if not filled before condition...
                    continue

                if trade.is_closing():
                    continue

                if not self.instrument.tradeable:
                    continue

                if trade.is_dirty:
                    # entry quantity changed need to update the exits orders
                    trade.update_dirty(trader, self.instrument)

                # potential order exec close price (always close a long)
                close_exec_price = self.instrument.close_exec_price(Order.LONG)

                if (trade.tp > 0) and (close_exec_price >= trade.tp) and not trade.has_limit_order():
                    # take profit trigger stop, close at market (taker fee)
                    if trade.close(trader, self.instrument):
                        # notify
                        self.strategy.notify_order(trade.id, Order.SHORT, self.instrument.market_id,
                                self.instrument.format_price(close_exec_price), timestamp, trade.timeframe,
                                'take-profit', trade.estimate_profit_loss(self.instrument))

                        # streaming (but must be done with notify)
                        if self._global_streamer:
                            self._global_streamer.member('buy-exit').update(close_exec_price, timestamp)

                elif (trade.sl > 0) and (close_exec_price <= trade.sl) and not trade.has_stop_order():
                    # stop loss trigger stop, close at market (taker fee)
                    if trade.close(trader, self.instrument):
                        # notify
                        self.strategy.notify_order(trade.id, Order.SHORT, self.instrument.market_id,
                                self.instrument.format_price(close_exec_price), timestamp, trade.timeframe,
                                'stop-loss', trade.estimate_profit_loss(self.instrument))

                        # streaming (but must be done with notify)
                        if self._global_streamer:
                            self._global_streamer.member('buy-exit').update(close_exec_price, timestamp)

            #
            # margin trade
            #

            elif trade.trade_type == StrategyTrade.TRADE_MARGIN or trade.trade_type == StrategyTrade.TRADE_IND_MARGIN:
                # process only on active trades
                if not trade.is_active():
                    # @todo timeout if not filled before condition...
                    continue

                if trade.is_closed():
                    continue

                if trade.is_closing():
                    continue

                if not self.instrument.tradeable:
                    continue

                # potential order exec close price
                close_exec_price = self.instrument.close_exec_price(trade.direction)

                if (trade.tp > 0) and ((trade.direction > 0 and close_exec_price >= trade.tp) or (trade.direction < 0 and close_exec_price <= trade.tp)) and not trade.has_limit_order():
                    # close in profit at market (taker fee)
                    if trade.close(trader, self.instrument):
                        # and notify
                        self.strategy.notify_order(trade.id, trade.close_direction(), self.instrument.market_id,
                                self.instrument.format_price(close_exec_price), timestamp, trade.timeframe,
                                'take-profit', trade.estimate_profit_loss(self.instrument))

                        # and for streaming
                        if self._global_streamer:
                            self._global_streamer.member('sell-exit' if trade.direction < 0 else 'buy-exit').update(close_exec_price, timestamp)

                elif (trade.sl > 0) and ((trade.direction > 0 and close_exec_price <= trade.sl) or (trade.direction < 0 and close_exec_price >= trade.sl)) and not trade.has_stop_order():
                    # close a long or a short position at stop-loss level at market (taker fee)
                    if trade.close(trader, self.instrument):
                        # and notify
                        self.strategy.notify_order(trade.id, trade.close_direction(), self.instrument.market_id,
                                self.instrument.format_price(close_exec_price), timestamp, trade.timeframe,
                                'stop-loss', trade.estimate_profit_loss(self.instrument))

                        # and for streaming
                        if self._global_streamer:
                            self._global_streamer.member('sell-exit' if trade.direction < 0 else 'buy-exit').update(close_exec_price, timestamp)

        self.unlock()

        #
        # remove terminated, rejected, canceled and empty trades
        #

        mutated = False

        self.lock()

        for trade in self.trades:
            if trade.can_delete():
                mutated = True

                # cleanup if necessary before deleting the trade related refs
                trade.remove(trader)

                # record the trade for analysis and study
                if not trade.is_canceled():
                    # last update of stats before logging
                    trade.update_stats(self.instrument.close_exec_price(trade.direction), timestamp)

                    # realized profit/loss
                    profit_loss = trade.profit_loss - trade.entry_fees_rate() - trade.exit_fees_rate()

                    # perf sommed here it means that its not done during partial closing
                    if profit_loss != 0.0:
                        self._stats['perf'] += profit_loss
                        self._stats['worst'] = min(self._stats['worst'], profit_loss)
                        self._stats['best'] = max(self._stats['best'], profit_loss)

                    if profit_loss <= 0.0:
                        self._stats['cont-loss'] += 1
                        self._stats['cont-win'] = 1

                    elif profit_loss > 0.0:
                        self._stats['cont-loss'] = 0
                        self._stats['cont-win'] += 1

                    record = {
                        'id': trade.id,
                        'eot': trade.entry_open_time,
                        'xot': trade.exit_open_time,
                        'd': trade.direction_to_str(),
                        'p': self.instrument.format_price(trade.entry_price),
                        'q': self.instrument.format_quantity(trade.order_quantity),
                        'e': self.instrument.format_quantity(trade.exec_entry_qty),
                        'x': self.instrument.format_quantity(trade.exec_exit_qty),
                        'tp': self.instrument.format_price(trade.take_profit),
                        'sl': self.instrument.format_price(trade.stop_loss),
                        'tf': timeframe_to_str(trade.timeframe),
                        'aep': self.instrument.format_price(trade.entry_price),
                        'axp': self.instrument.format_price(trade.exit_price),
                        's': trade.state_to_str(),
                        'b': self.instrument.format_price(trade.best_price()),
                        'w': self.instrument.format_price(trade.worst_price()),
                        'bt': trade.best_price_timestamp(),
                        'wt': trade.worst_price_timestamp(),
                        'pl': profit_loss,
                        'fees': trade.entry_fees_rate() + trade.exit_fees_rate(),
                        'c': trade.get_conditions(),
                        'com': trade.comment,
                    }

                    if profit_loss < 0:
                        self._stats['failed'].append(record)
                    elif profit_loss > 0:
                        self._stats['success'].append(record)
                    else:
                        self._stats['roe'].append(record)

                    if self._reporting == StrategyTrader.REPORTING_VERBOSE:
                        self.report(trade, False)

        # recreate the list of trades
        if mutated:
            trades_list = []

            for trade in self.trades:
                if not trade.can_delete():
                    # keep only active and pending trades
                    trades_list.append(trade)

            self.trades = trades_list

        self.unlock()
コード例 #17
0
ファイル: exporter.py プロジェクト: venkiiee/siis
def do_exporter(options):
    Terminal.inst().info("Starting SIIS exporter...")
    Terminal.inst().flush()

    # database manager
    Database.create(options)
    Database.inst().setup(options)

    broker_id = options['broker']
    market_id = options['market']

    timeframe = None

    # UTC option dates
    from_date = options.get('from')
    to_date = options.get('to')

    if not to_date:
        today = datetime.now().astimezone(UTC())

        if timeframe == Instrument.TF_MONTH:
            to_date = today + timedelta(months=1)
        else:
            to_date = today + timedelta(seconds=timeframe or 1.0)

        to_date = to_date.replace(microsecond=0)

    if not options.get('timeframe'):
        timeframe = None
    else:
        if options['timeframe'] in TIMEFRAME_FROM_STR_MAP:
            timeframe = TIMEFRAME_FROM_STR_MAP[options['timeframe']]
        else:
            try:
                timeframe = int(options['timeframe'])
            except:
                pass

    filename = options.get('filename')

    cur_datetime = datetime.now().astimezone(
        UTC()).strftime("%Y-%m-%dT%H:%M:%SZ")
    from_date_str = from_date.strftime("%Y-%m-%dT%H:%M:%SZ")
    to_date_str = to_date.strftime("%Y-%m-%dT%H:%M:%SZ")

    try:
        # exporting data...
        if timeframe is None:
            for market in options['market'].split(','):
                if market.startswith('!') or market.startswith('*'):
                    continue

                dst = open("%s-%s-%s-any.siis" % (filename, broker_id, market),
                           "wt")

                # write file header
                dst.write(
                    "format=SIIS\tversion=%s\tcreated=%s\tbroker=%s\tmarket=%s\tfrom=%s\tto=%s\ttimeframe=any\n"
                    % (EXPORT_VERSION, cur_datetime, broker_id, market,
                       from_date_str, to_date_str))

                for tf in EXPORT_TF:
                    Terminal.inst().info("Exporting %s OHLC %s..." %
                                         (market, timeframe_to_str(tf)))

                    dst.write("timeframe=%s\n" % timeframe_to_str(tf))
                    export_ohlcs_siis_1_0_0(options['broker'], market, tf,
                                            from_date, to_date, dst)

                dst.close()
                dst = None

        elif timeframe == Instrument.TF_TICK:
            for market in options['market'].split(','):
                if market.startswith('!') or market.startswith('*'):
                    continue

                dst = open("%s-%s-%s-t.siis" % (filename, broker_id, market),
                           "wt")

                # write file header
                dst.write(
                    "format=SIIS\tversion=%s\tcreated=%s\tbroker=%s\tmarket=%s\tfrom=%s\tto=%s\ttimeframe=t\n"
                    % (EXPORT_VERSION, cur_datetime, broker_id, market,
                       from_date_str, to_date_str))

                Terminal.inst().info("Exporting %s ticks/trades..." %
                                     (market, ))

                dst.write("timeframe=t\n")
                export_ticks_siis_1_0_0(options['broker'], market, from_date,
                                        to_date, dst)

                dst.close()
                dst = None

        elif timeframe > 0:
            # particular ohlc
            for market in options['market'].split(','):
                if market.startswith('!') or market.startswith('*'):
                    continue

                dst = open(
                    "%s-%s-%s-%s.siis" %
                    (filename, broker_id, market, timeframe_to_str(timeframe)),
                    "wt")

                # write file header
                dst.write(
                    "format=SIIS\tversion=%s\tcreated=%s\tbroker=%s\tmarket=%s\tfrom=%s\tto=%s\ttimeframe=%s\n"
                    %
                    (EXPORT_VERSION, cur_datetime, broker_id, market,
                     from_date_str, to_date_str, timeframe_to_str(timeframe)))

                Terminal.inst().info("Exporting %s OHLC %s..." %
                                     (market, timeframe_to_str(timeframe)))

                dst.write("timeframe=%s\n" % timeframe_to_str(timeframe))
                export_ohlcs_siis_1_0_0(options['broker'], market, timeframe,
                                        from_date, to_date, dst)

                dst.close()
                dst = None

    except KeyboardInterrupt:
        pass
    except Exception as e:
        error_logger.error(str(e))
        dst.close()
        dst = None
    finally:
        pass

    Database.terminate()

    Terminal.inst().info("Exportation done!")
    Terminal.inst().flush()

    Terminal.terminate()
    sys.exit(0)