Ejemplo n.º 1
0
    def _reset_broker_tuple(self, *args, **kwargs):
        '''
            extract broker data
        '''
        broker_tuple = kwargs.get("broker", None)

        if broker_tuple:
            self.__clock = broker_tuple.clock
            self.__asset_finder = broker_tuple.asset_finder
            self.__broker_api = broker_tuple.broker
            self.__data_portal = broker_tuple.data_portal
            self.__auth = broker_tuple.auth

        else:
            self.__clock = kwargs.get("clock", self.__clock)
            self.__asset_finder = kwargs.get("asset_finder",
                                             self.__asset_finder)
            self.__broker_api = kwargs.get("api", self.__broker_api)
            self.__data_portal = kwargs.get("data_portal", self.__data_portal)
            self.__auth = kwargs.get("auth", self.__auth)

        # check for valid object types
        if self.__clock:
            if not isinstance(self.__clock, TradingClock):
                raise ValidationError(msg="clock supplied is of "
                                      "illegal type")
        if self.__asset_finder:
            if not isinstance(self.__asset_finder, AssetFinder):
                raise ValidationError(msg="asset finder supplied is of "
                                      "illegal type")
        if self.__data_portal:
            if not isinstance(self.__data_portal, DataPortal):
                raise ValidationError(msg="data portal supplied is of "
                                      "illegal type")
        if self.__broker_api:
            if not isinstance(self.__broker_api, AbstractBrokerAPI):
                raise ValidationError(msg="data portal supplied is of "
                                      "illegal type")
        if self.__auth:
            if not isinstance(self.__auth, AbstractAuth):
                raise ValidationError(msg="authentication supplied is of "
                                      "illegal type")

        self.__broker_tuple = Broker(self.__auth, self.__asset_finder,
                                     self.__data_portal, self.__broker_api,
                                     self.__clock,
                                     self.__broker_api._mode_supports)

        # authentication object can be null for backtester
        if self.__asset_finder and self.__data_portal and\
            self.__broker_api and self.__clock:
            self.__broker_initialized = True
Ejemplo n.º 2
0
    def live_run(self, alert_manager=None, publish_packets=False):
        '''
            The entry point for a live run.
        '''
        if self.mode != MODE.LIVE:
            raise StateMachineError(msg="mode must be live")

        if not self.context.is_initialized():
            raise InitializationError(msg="context is not "
                                      "properly initialized")

        if not isinstance(self.context.clock, RealtimeClock):
            raise ValidationError(msg="clock must be real-time clock")

        # reset the clock at the start of the run, this also aligns
        # ticks to the nearest rounded bar depending on the frequency
        self._reset_clock(self.context.clock.emit_frequency)

        # initialize the coroutines
        clock_coro = self.context.clock.tick()
        algo_coro = self._run_live(alert_manager, publish_packets)

        try:
            tasks = asyncio.gather(clock_coro,
                                   algo_coro,
                                   return_exceptions=False)
            self._loop.run_until_complete(tasks)
        except BaseException as e:
            # TODO: do a proper exception handling here
            print("exception {}".format(e))
            tasks.cancel()
            raise e
        finally:
            self._loop.close()
Ejemplo n.º 3
0
    def _reset_parent(self, *args, **kwargs):
        new_parent = kwargs.get("parent", None)

        if new_parent:
            if not isinstance(self.parent, AlgoContext):
                raise ValidationError(msg="context parent is of "
                                      "invalid type",
                                      handling=ExceptionHandling.IGNORE)
        self.parent = new_parent
Ejemplo n.º 4
0
 def save_config(self, file_path):
     '''
         Write config to a file.
     '''
     try:
         with open(file_path, 'w') as config_file:
             json.dump(self.to_dict(), config_file)
     except FileNotFoundError:
         msg='missing config file {config_file}'
         raise ValidationError(msg=msg)
Ejemplo n.º 5
0
    def cancel_order(self, order_param):
        '''
            Cancel existing order if not already executed.
        '''
        if not self.is_TRADING_BAR():
            msg = f"can't cancel order, market not open."
            raise ValidationError(msg=msg)

        order_id = order_param.oid if isinstance(order_param, Order)\
                        else order_param

        return self.context.broker.cancel_order(order_id)
Ejemplo n.º 6
0
    def _back_test_generator(self, alert_manager=None):
        '''
            The entry point for backtest run. This generator yields
            the current day performance.
        '''
        if self.mode != MODE.BACKTEST:
            raise StateMachineError(msg="mode must be back-test")

        if not self.context.is_initialized():
            raise InitializationError(msg="context is not "
                                      "properly initialized")

        if not isinstance(self.context.clock, SimulationClock):
            raise ValidationError(msg="clock must be simulation clock")

        self._make_broker_dispatch()  # only useful for backtest

        for t, bar in self.context.clock:
            try:
                ts = pd.Timestamp(t,
                                  unit='ns',
                                  tz=self.context.trading_calendar.tz)

                if bar == BARS.ALGO_START:
                    self.context.set_up(timestamp=ts)

                self.context.set_timestamp(ts)
                self._BROKER_FUNC_DISPATCH.get(bar, self._bar_noop)(ts)

                if bar == BARS.TRADING_BAR:
                    #self.context.BAR_update(ts)
                    pass

                if bar == BARS.AFTER_TRADING_HOURS:
                    #self.context.BAR_update(ts)
                    self.context.EOD_update(ts)
                    perf = self.context.performance
                    perf['timestamp'] = str(self.context.timestamp)
                    yield perf

                self._USER_FUNC_DISPATCH.get(bar, self._bar_noop)(ts)

            except BlueShiftException as e:
                if not alert_manager:
                    raise e
                else:
                    timestamp = self.context.timestamp
                    alert_manager.handle_error(e,
                                               'algorithm',
                                               mode=self.mode,
                                               timestamp=timestamp)
                    continue
Ejemplo n.º 7
0
    def _create(self, *args, **kwargs):
        # pylint: disable=bad-super-call
        access_token = kwargs.pop('access_token', None)
        server = kwargs.pop('server', 'real')
        proxy_url = kwargs.pop('proxy_url', None)
        proxy_port = kwargs.pop('proxy_port', None)
        proxy_type = kwargs.pop('proxy_type', None)
        log_file = kwargs.pop('log_file', None)
        log_level = kwargs.pop('log_level', 'error')
        config_file = kwargs.pop('config_file', '')

        try:
            fxcmpyapi.__init__(self, access_token, config_file, log_file,
                               log_level, server, proxy_url, proxy_port,
                               proxy_type)
        except ServerError:
            msg = "access token missing"
            handling = ExceptionHandling.TERMINATE
            raise AuthenticationError(msg=msg, handling=handling)

        except RequestException as e:
            msg = "in broker.auth: " + str(e)
            handling = ExceptionHandling.WARN
            raise AuthenticationError(msg=msg, handling=handling)

        logger = get_logger()
        if logger:
            self.logger = logger

        APIRateLimitMixin.__init__(self, *args, **kwargs)

        # max instruments that can be queried at one call
        self._max_instruments = kwargs.pop("max_instruments", None)
        self._trading_calendar = kwargs.get("trading_calendar", None)

        if not self._rate_limit:
            # TODO: check FXCM rate limits
            self._rate_limit = 2
            self._rate_limit_count = self._rate_limit

        if not self._rate_period:
            self._rate_period = 1

        if not self._max_instruments:
            # 50 covers all currency pairs (at present 38)
            self._max_instruments = 50

        # we reset this value on first call
        self._rate_limit_since = None

        if not self._trading_calendar:
            raise ValidationError(msg="missing calendar")
Ejemplo n.º 8
0
    def set_up(self, *args, **kwargs):
        '''
            Setting up the context before the algo start, or at any 
            re-start, initializes timestamp and performance object
        '''
        timestamp = kwargs.get("timestamp", None)
        if not timestamp:
            raise InitializationError(msg="timestamp required"
                                      " to initialize"
                                      " context")
        if not isinstance(timestamp, pd.Timestamp):
            raise ValidationError(msg="timestamp must be of type" " Timestamp")
        self.__timestamp = timestamp

        self._reset_performance(*args, **kwargs)
Ejemplo n.º 9
0
    def _save_position_transactions(self, timestamp=None):
        pos_write = {}
        try:
            for pos in self._current_pos:
                pos_write[pos.symbol] = self._current_pos[pos].to_json()
        except (TypeError, KeyError, BlueShiftException):
            raise ValidationError(msg="corrupt positions data in blotter.")
        else:
            try:
                if pos_write:
                    with open(self._pos_fname, 'w') as fp:
                        json.dump(pos_write, fp)
            except (TypeError, OSError):
                msg = f"failed to write blotter data to {self._pos_fname}"
                handling = ExceptionHandling.WARN
                raise DataWriteException(msg=msg, handling=handling)

        self._txns_tracker._save_transactions_list(timestamp)
Ejemplo n.º 10
0
    def update_instruments_list(self, instruments_list=None, valid_till=None):
        '''
            Download the instruments list for the day, if not already
            downloaded before. If we fail, we cannot continue and so
            raise a TERMINATE level exception.
        '''
        if instruments_list is not None:
            if not isinstance(instruments_list, pd.DataFrame):
                msg = "Invalid instruments list for {self.name}"
                handling = ExceptionHandling.TERMINATE
                raise ValidationError(msg=msg, handling=handling)
            self._instruments_list = instruments_list
            # check or set the expiry
            if valid_till is not None:
                # TODO: check for consistent timezone
                self._instruments_list_valid_till = valid_till
            else:
                t = pd.Timestamp.now(tz=self.tz) + pd.Timedelta(days=1)
                self._instruments_list_valid_till = t.normalize()

        if self._instruments_list is not None:
            t = pd.Timestamp.now(tz=self.tz)
            if t < self._instruments_list_valid_till:
                return

        try:
            self._instruments_list = pd.DataFrame(self._api.\
                                            instruments())
            self._filter_instruments_list()
            self._extract_expiries_underlyings()
            t = pd.Timestamp.now(tz=self.tz) + pd.Timedelta(days=1)
            self._instruments_list_valid_till = t.normalize()
        except KiteException as e:
            msg = str(e)
            handling = ExceptionHandling.TERMINATE
            raise APIException(msg=msg, handling=handling)
        except RequestException as e:
            msg = str(e)
            handling = ExceptionHandling.TERMINATE
            raise APIException(msg=msg, handling=handling)
Ejemplo n.º 11
0
    def _reset_performance(self, *args, **kwargs):
        self.__performance = kwargs.get("perf", None)

        if not self.__performance:
            timestamp = kwargs.get("timestamp", None)
            if not timestamp:
                raise InitializationError(msg="timestamp required"
                                          " to initialize"
                                          " context")
            if not isinstance(timestamp, pd.Timestamp):
                raise ValidationError(msg="timestamp must be of type"
                                      " Timestamp")
            if not self.__tracker_initialized:
                raise InitializationError(msg="accounts still not "
                                          "initialized")

            self.__performance = Performance(self.__account,
                                             self.__timestamp.value)

        if not isinstance(self.__performance, Performance):
            raise InitializationError(msg="accounts still not " "initialized")

        self._perf_initialized = True
Ejemplo n.º 12
0
    def _create(self, *args, **kwargs):
        # pylint: disable=bad-super-call
        #super(self.__class__, self).__init__(*args, **kwargs)
        api_key = kwargs.pop('api_key', None)
        access_token = kwargs.pop('access_token', None)
        root = kwargs.pop('root', None)
        debug = kwargs.pop('debug', False)
        timeout = kwargs.pop('timeout', None)
        proxies = kwargs.pop('proxies', None)
        pool = kwargs.pop('pool', None)
        disable_ssl = kwargs.pop('disable_ssl', False)

        KiteConnect.__init__(self, api_key, access_token, root, debug, timeout,
                             proxies, pool, disable_ssl)
        APIRateLimitMixin.__init__(self, *args, **kwargs)

        # max instruments that can be queried at one call
        self._max_instruments = kwargs.pop("max_instruments", None)
        self._trading_calendar = kwargs.get("trading_calendar", None)

        if not self._rate_limit:
            # Kite has 3 per sec, we are conservative
            self._rate_limit = 2
            self._rate_limit_count = self._rate_limit

        if not self._rate_period:
            self._rate_period = 1

        if not self._max_instruments:
            # max allowed is 500 for current, and one for history
            self._max_instruments = 50

        # we reset this value on first call
        self._rate_limit_since = None

        if not self._trading_calendar:
            raise ValidationError(msg="missing calendar")
Ejemplo n.º 13
0
    def _asset_from_sym(self, sym):
        '''
            Create an asset from a matching entry in the instruments list.
        '''
        # pylint: disable=no-self-use
        # TODO: replace this by create_asset_from_dict from _assets
        # all instrument types are Forex.
        sym = sym.split(":")[0]

        if sym not in self._instruments_list:
            raise SymbolNotFound(f"no instruments with symbol {sym}")

        base, quote = tuple(sym.split('/'))

        if not base or not quote:
            raise ValidationError(f"Invalid symbol {sym} for Forex.")

        # TODO: hardcoded assumptions here on ticksize, generalize this.
        # NOTE: actual tick size is the inverse of this number!!
        if quote == 'JPY':
            tick_size = 100
        else:
            tick_size = 10000

        asset = Forex(
            -1,
            symbol=sym,
            ccy_pair=base + '/' + quote,
            base_ccy=base,
            quote_ccy=quote,
            name=sym,
            mult=1000,  # the micro-lot
            tick_size=tick_size,
            ccy=quote,
            exchange_name='FXCM')

        return asset