Ejemplo n.º 1
0
    def current(self, assets, fields):
        '''
            Fetch the current bar for the given assets and fields.
        '''
        if not isinstance(assets, list):
            assets = [assets]
        if not isinstance(fields, list):
            fields = [fields]

        # prune the list if we exceed max instruments
        if len(assets) > self._api._max_instruments:
            assets = assets[:self._api._max_instruments]

        data = []
        try:
            for asset in assets:
                df = self._get_candles(asset, fields)
                if len(assets) == 1 and len(fields) == 1:
                    return df.iloc[0, 0]
                elif len(assets) == 1:
                    return df.iloc[0]
                data.append(df)

            data = pd.concat(data)
            data.index = assets
            return data
        except (ValueError, TypeError, ServerError) as e:
            msg = "in data.current: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
        except RequestException as e:
            msg = "in data.current: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 2
0
 def account(self):
     '''
         This will call positions and update the accounts
         and return.
     '''
     last_version = self._account
     try:
         data = self._api.get_accounts().T
         cash = sum(data.loc['usableMargin', ])
         margin = sum(data.loc['usdMr', ])
         _positions = self.positions
         self._account.update_account(cash, margin, _positions)
         return self._account.to_dict()
     except (ValueError, TypeError, ServerError) as e:
         if isinstance(e, ServerError):
             self._account = last_version
             return self._account.to_dict()
         else:
             self._account = last_version
             msg = "in broker.account: " + str(e)
             handling = ExceptionHandling.WARN
             raise BrokerAPIError(msg=msg, handling=handling)
     except RequestException as e:
         self._account = last_version
         msg = "in broker.account: " + str(e)
         handling = ExceptionHandling.WARN
         raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 3
0
    def positions(self):
        '''
            Fetch the positions
        '''
        try:
            position_details = self._api.positions()
            if not position_details:
                return self._open_positions

            position_details = position_details['net']
            for p in position_details:
                asset, position = self._position_from_dict(p)
                self._open_positions[asset] = position
                if self._open_positions[asset].if_closed():
                    self._closed_positions.append(
                        self._open_positions.pop(asset))

            return self._open_positions
        except KiteException as e:
            msg = str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
        except RequestException as e:
            msg = str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 4
0
 def account(self):
     '''
         This will call positions and update the accounts
         and return.
     '''
     last_version = self._account
     try:
         data = self._api.margins()
         cash = data['equity']['available']['cash'] +\
             data['equity']['available']['intraday_payin']-\
             data['equity']['utilised']['payout'] +\
             data['equity']['utilised']['m2m_realised']
         margin = data['equity']['utilised']['exposure'] +\
             data['equity']['utilised']['span'] +\
             data['equity']['utilised']['option_premium']
         _positions = self.positions
         self._account.update_account(cash, margin, _positions)
         return self._account.to_dict()
     except KiteException as e:
         if isinstance(e, NetworkException):
             self._account = last_version
             return self._account.to_dict()
         else:
             msg = str(e)
             handling = ExceptionHandling.WARN
             raise BrokerAPIError(msg=msg, handling=handling)
     except RequestException as e:
         msg = str(e)
         handling = ExceptionHandling.WARN
         raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 5
0
    def orders(self, *args, **kwargs):
        '''
            Fetch a list of orders from the broker and update
            internal dicts. Returns both open and closed orders.
        '''
        try:
            orders = self._api.orders()
            if orders is None:
                return {**self._open_orders, **self._closed_orders}

            for o in orders:
                # we assume no further updates on closed orders
                if o['order_id'] in self._closed_orders:
                    continue

                order_id, order = self._order_from_dict(o)
                if order.status == OrderStatus.OPEN:
                    self._open_orders[order_id] = order
                else:
                    # add to closed orders dict
                    self._closed_orders[order_id] = order
                    # pop from open order if it was there
                    if order_id in self._open_orders:
                        self._open_orders.pop(order_id)

            return {**self._open_orders, **self._closed_orders}
        except KiteException as e:
            msg = str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
        except RequestException as e:
            msg = str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 6
0
    def close_position(self, trade_id, amount, time_in_force='DAY', rate=None):
        '''
            Implement close_trade.
        '''
        try:
            trade_id = str(trade_id)
            if str(trade_id) in self._trading_cache:
                position = self._trading_cache[trade_id]
            else:
                _ = self.positions
                if str(trade_id) not in self._trading_cache:
                    raise UnsupportedOrder(msg="Trade not found")
                position = self._trading_cache[trade_id]

            mult = position.asset.mult
            amount = int(amount / mult)
            self._api.close_trade(trade_id,
                                  amount,
                                  order_type='AtMarket',
                                  time_in_force=time_in_force,
                                  rate=rate)
        except (ValueError, TypeError, ServerError) as e:
            msg = "in broker.close_position: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
        except RequestException as e:
            msg = "in broker.close_position: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 7
0
    def square_off(self, symbols=None, time_in_force='GTC', account_id=None):
        '''
            Do close_all or close_all_for_symbol if symbols are 
            supplied. This will sqaure off all positions for a 
            particular FX pair or all positions.
        '''
        try:
            if symbols:
                for sym in symbols:
                    self._api.close_all_for_symbol(sym,
                                                   order_type='AtMarket',
                                                   time_in_force=time_in_force,
                                                   account_id=account_id)
            else:
                self._api.close_all(order_type='AtMarket',
                                    time_in_force=time_in_force,
                                    account_id=account_id)

        except (ValueError, TypeError, ServerError) as e:
            msg = "in broker.square_off: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
        except RequestException as e:
            msg = "in broker.square_off: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 8
0
 def cancel_order(self, order_param):
     '''
         Cancel an existing order
     '''
     if isinstance(order_param, Order):
         order_id = order_param.oid
         variety = order_param.order_flag
         parent_order_id = order_param.parent_order_id
     else:
         order_id = order_param
         order = self._open_orders.get(order_id, None)
         if order:
             variety = order_param.order_flag
             parent_order_id = order_param.parent_order_id
         else:
             variety = OrderFlag.NORMAL
             parent_order_id = None
     try:
         variety = order_flag_map.get(variety, "regular")
         order_id = self._api.cancel_order(variety, order_id,
                                           parent_order_id)
         return order_id
     except KiteException as e:
         msg = str(e)
         handling = ExceptionHandling.WARN
         raise BrokerAPIError(msg=msg, handling=handling)
     except RequestException as e:
         msg = str(e)
         handling = ExceptionHandling.WARN
         raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 9
0
    def place_order(self, order):
        '''
            Place a new order. Order asset will be converted to
            an asset understood by the broker.
        '''
        quantity = order.quantity

        asset = self._asset_finder.symbol_to_asset(order.asset.symbol)
        tradingsymbol = asset.symbol

        is_buy = False if order.side > 0 else True
        order_type = order.order_type

        price = order.price  # limit price
        validity = order.order_validity
        # TODO: we track algo by adding a specifc account id
        # generalize this. Must have broker support to implement.
        tag = order.tag
        tag = tag if tag in self._api.account_ids else None

        validity = order_validity_map.teg(validity, 'DAY')

        #TODO: assumption price cannot be negative - validate.
        price = price if price > 0 else 0

        lots = int(quantity / asset.mult)
        try:
            if order_type > 1:
                raise UnsupportedOrder(msg="Unsupported order type")

            if price > 0:
                order_id = self._create_entry_order(symbol=tradingsymbol,
                                                    is_buy=is_buy,
                                                    amount=lots,
                                                    time_in_force=validity,
                                                    limit=price,
                                                    is_in_pips=False,
                                                    account_id=tag)
            else:
                if is_buy > 0:
                    # we buy!
                    order_obj = self._api.create_market_buy_order(
                        tradingsymbol, lots, account_id=tag)
                else:
                    # we sell!
                    order_obj = self._api.create_market_sell_order(
                        tradingsymbol, lots, account_id=tag)
                order_id = order_obj.get_orderId()

            return order_id
        except (ValueError, TypeError, ServerError) as e:
            msg = "in broker.place_order: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
        except RequestException as e:
            msg = "in broker.place_order: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 10
0
 def place_order(self, order):
     '''
         Place a new order. Order asset will be converted to
         an asset understood by the broker.
     '''
     quantity = order.quantity
     variety = order.order_flag
     
     asset = self._aset_finder.symbol_to_asset(
             order.asset.symbol)
     exchange = asset.exchange_name
     tradingsymbol = asset.symbol
         
     transaction_type = order.side
     product = order.product_type
     order_type = order.order_type
     price = order.price
     validity = order.order_validity
     disclosed_quantity = order.disclosed
     trigger_price = order.trigger_price
     stoploss_price = order.stoploss_price
     tag = order.tag
     
     variety = order_flag_map.teg(variety,"regular")
     transaction_type = order_side_map.teg(
             transaction_type, None)
     order_type = order_type_map.teg(order_type,"MARKET")
     product = product_type_map.teg(product,'NRML')
     validity = order_validity_map.teg(validity, 'DAY')
     
     #TODO: assumption price cannot be negative
     price = price if price > 0 else None
     trigger_price = trigger_price if price > 0 else None
     stoploss_price = stoploss_price if price > 0 else None
     
     try:
         order_id = self._api.place_order(variety, exchange,
                               tradingsymbol,
                               transaction_type,
                               quantity, product,
                               order_type, price=price,
                               validity=validity,
                               disclosed_quantity=\
                                   disclosed_quantity,
                               trigger_price=trigger_price,
                               stoploss=stoploss_price, 
                               tag=tag)
         return order_id
     except KiteException as e:
         msg = str(e)
         handling = ExceptionHandling.WARN
         raise BrokerAPIError(msg=msg, handling=handling)
     except RequestException as e:
         msg = str(e)
         handling = ExceptionHandling.WARN
         raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 11
0
 def fund_transfer(self, amount):
     '''
         We do not implement fund transfer for Zerodha.
     '''
     msg = "Please go to Zerodha website for fund transfer"
     handling = ExceptionHandling.WARN
     raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 12
0
 def update_order(self, order_param, *args, **kwargs):
     '''
         Update an existing order.
     '''
     if isinstance(order_param, Order):
         order_id = order_param.oid
         variety = order_param.order_flag
         parent_order_id = order_param.parent_order_id
     else:
         order_id = order_param
         order = self._open_orders.get(order_id,None)
         if order:
             variety = order_param.order_flag
             parent_order_id = order_param.parent_order_id
         else:
             variety = OrderFlag.NORMAL
             parent_order_id = None
             
     quantity = kwargs.pop("quantity",None)
     price = kwargs.pop("price",None)
     order_type = kwargs.pop("order_type",None)
     trigger_price = kwargs.pop("trigger_price",None)
     validity = kwargs.pop("validity",None)
     disclosed_quantity = kwargs.pop("disclosed_quantity",None)
     
     try:
         variety = order_flag_map.teg(variety,"regular")
         order_type = order_type_map.teg(order_type,"MARKET")
         validity = order_validity_map.teg(validity, 'DAY')
         order_id = self._api.modify_order(variety,order_id,
                                parent_order_id,
                                quantity,
                                price,
                                order_type,
                                trigger_price,
                                validity,
                                disclosed_quantity)
         return order_id
     except KiteException as e:
         msg = str(e)
         handling = ExceptionHandling.WARN
         raise BrokerAPIError(msg=msg, handling=handling)
     except RequestException as e:
         msg = str(e)
         handling = ExceptionHandling.WARN
         raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 13
0
 def profile(self):
     '''
         Fetch and return the user profile.
     '''
     try:
         return self._api.profile()
     except KiteException as e:
         msg = str(e)
         handling = ExceptionHandling.LOG
         raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 14
0
    def history(self, assets, fields, nbar, frequency):
        '''
            Fetch the historical bar for the given assets and fields.
            Minute data max length is 10K, we use the same cap for 
            daily data as well.
        '''
        if not isinstance(assets, list):
            assets = [assets]
        if not isinstance(fields, list):
            fields = [fields]

        # prune the list if we exceed max instruments
        if len(assets) > self._api._max_instruments:
            assets = assets[:self._api._max_instruments]

        # check and map the data frequency
        frequency = frequency.lower()
        if frequency not in ['1m', '1d']:
            raise UnsupportedFrequency(msg=frequency)
        period = 'm1' if frequency == '1m' else 'D1'

        # cap the max period length
        nbar = int(nbar)
        if nbar > 10000:
            nbar = 10000

        data = {}
        try:
            for asset in assets:
                df = self._get_candles(asset, fields, nbar=nbar, period=period)
                if len(assets) == 1:
                    return df
                data[asset] = df

            return pd.concat(data)
        except (ValueError, TypeError, ServerError) as e:
            msg = "in data.history: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
        except RequestException as e:
            msg = "in data.history: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 15
0
 def cancel_order(self, order_param):
     '''
         Cancel an existing order
     '''
     if isinstance(order_param, Order):
         order_id = order_param.oid
     else:
         order_id = order_param
     try:
         self._api.delete_order(order_id)
         return order_id
     except (ValueError, TypeError, ServerError) as e:
         msg = "in broker.cancel_order: " + str(e)
         handling = ExceptionHandling.WARN
         raise BrokerAPIError(msg=msg, handling=handling)
     except RequestException as e:
         msg = "in broker.cancel_order: " + str(e)
         handling = ExceptionHandling.WARN
         raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 16
0
 def process_response(self, response):
     '''
         We probably do not need this as we use the pyconnect
         package which does this for us already.
     '''
     if response['status'] == ResponseType.SUCCESS.value:
         return response['data']
     else:
         msg = response['data']
         raise BrokerAPIError(msg=msg)
Ejemplo n.º 17
0
    def open_orders(self):
        '''
            Call the order method and return the open order dict.
        '''
        try:
            last_version = self._open_orders
            self._open_orders = {}
            orders = self._api.get_orders(kind='list')
            for order in orders:
                # TODO: fixes some strange orders without currency field
                if not order['currency']: continue
                order_id, order = self._order_from_dict(order)
                self._open_orders[order_id] = order
            # cehck missing keys
            missing = [k for k in last_version if k not in self._open_orders]
            '''
                these missing can either be cancelled, or converted to 
                position. Save them to internal missing list to update
                them later.
            '''
            for m in missing:
                # missing map is keyed to trade ID, unlike orders dicts
                # also we store the trade ID in the broker_order_id field.
                missing_order = last_version[m]
                self._missing_orders[missing_order.broker_order_id] =\
                                                            missing_order

            return self._open_orders
        except (ValueError, TypeError, ServerError) as e:
            if isinstance(e, ServerError):
                self._open_orders = last_version
                return self._open_orders
            else:
                self._open_orders = last_version
                msg = "in broker.open_orders: " + str(e)
                handling = ExceptionHandling.WARN
                raise BrokerAPIError(msg=msg, handling=handling)
        except RequestException as e:
            self._open_orders = last_version
            msg = "in broker.open_orders: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 18
0
 def order(self, order_id):
     '''
         Fetch the order by id.
     '''
     try:
         order = self._api.get_order(order_id)
         oid, order = self._order_from_dict(self._fxcm_order_to_dict(order))
         return order
     except ValueError as e:
         msg = "in broker.order: " + str(e)
         handling = ExceptionHandling.WARN
         raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 19
0
 def profile(self):
     '''
         Fetch and return the user profile.
     '''
     try:
         default_account = self._api.default_account
         accounts = self._api.account_ids
         return {'default_account':default_account,
                 'account_ids':accounts}
     except KiteException as e:
         msg = str(e)
         handling = ExceptionHandling.LOG
         raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 20
0
    def positions(self):
        '''
            Fetch the positions
        '''
        try:
            last_version = self._open_positions
            # check if there is a new addition to closed position
            position_details = self._api.get_closed_positions(kind='list')
            for p in position_details:
                asset, position = self._position_from_dict(p, closed=True)
                if position:
                    self._closed_positions.append(position)

            # open positions are processed afresh each time
            position_details = self._api.get_open_positions(kind='list')
            self._create_pos_dict(position_details)

            # now we are left with orders which were cancelled, apparently.
            for key in list(self._missing_orders.keys()):
                self._missing_orders[key].partial_cancel()
                oid = self._missing_orders[key].oid
                self._closed_orders[oid] = self._missing_orders.pop(key)

            # just to make sure!
            self._missing_orders = {}

            return self._open_positions
        except (ValueError, TypeError, ServerError) as e:
            self._open_positions = last_version
            msg = "in broker.positions: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
        except RequestException as e:
            self._open_positions = last_version
            msg = str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 21
0
    def update_order(self, order_param, *args, **kwargs):
        '''
            Update an existing order.
        '''
        if isinstance(order_param, Order):
            order_id = order_param.oid
        else:
            order_id = order_param

        try:
            order = self.order(order_id)
            quantity = kwargs.pop("quantity", order.quantity)
            price = kwargs.pop("price", order.price)
            lots = int(quantity / order.asset.mult)
            self._api.change_order(order_id, lots, price)
            return order_id
        except (ValueError, TypeError, ServerError) as e:
            msg = "in broker.update_order: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
        except RequestException as e:
            msg = "in broker.update_order: " + str(e)
            handling = ExceptionHandling.WARN
            raise BrokerAPIError(msg=msg, handling=handling)
Ejemplo n.º 22
0
 def process_response(self, response):
     if response['status'] == ResponseType.SUCCESS.value:
         return response['data']
     else:
         msg = response['data']
         raise BrokerAPIError(msg=msg)
Ejemplo n.º 23
0
    def _create_entry_order(self,
                            symbol,
                            is_buy,
                            amount,
                            time_in_force,
                            limit=0,
                            is_in_pips=False,
                            account_id=None):
        '''
            Implements FXCM entry_order without the pesky `limit` thingy.
        '''
        if account_id is None:
            account_id = self._api.default_account
        else:
            try:
                account_id = int(account_id)
            except:
                raise TypeError('account_id must be an integer.')

        if account_id not in self._api.account_ids:
            raise ValueError('Unknown account id %s.' % account_id)

        try:
            amount = int(amount)
        except:
            raise TypeError('Order amount must be an integer.')

        if symbol not in self._api.instruments:
            raise ValueError('Unknown symbol %s.' % symbol)

        try:
            limit = float(limit)
        except:
            raise TypeError('rate must be a number.')

        order_type = "Entry"

        if time_in_force not in ['GTC', 'DAY', 'GTD', 'IOC', 'FOK']:
            msg = "time_in_force must be 'GTC', 'DAY', 'IOC', 'FOK', or 'GTD'."
            raise ValueError(msg)

        if is_in_pips is True:
            is_in_pips = 'true'
        elif is_in_pips is False:
            is_in_pips = 'false'
        else:
            raise ValueError('is_in_pips must be True or False.')

        if is_buy is True:
            is_buy = 'true'
        elif is_buy is False:
            is_buy = 'false'
        else:
            raise ValueError('is_buy must be True or False.')

        params = {
            'account_id': account_id,
            'symbol': symbol,
            'is_buy': is_buy,
            'rate': limit,
            'amount': amount,
            'order_type': order_type,
            'is_in_pips': is_in_pips,
            'time_in_force': time_in_force
        }
        data = self._api.__handle_request__(
            method='trading/create_entry_order',
            params=params,
            protocol='post')

        if 'data' in data and 'orderId' in data['data']:
            order_id = int(data['data']['orderId'])
            return order_id

        raise BrokerAPIError(msg='Missing orderId in servers answer.')
        return 0