def fetch_market(self, epic): """ Fetch and cache it. It rarely changes, except for base exchange rate, so assume it once for all. """ market_info = self._connector.market(epic) instrument = market_info['instrument'] snapshot = market_info['snapshot'] dealing_rules = market_info['dealingRules'] market = Market(epic, instrument['marketId']) # cannot interpret this value because IG want it as it is market.expiry = instrument['expiry'] # not perfect but IG does not provides this information if instrument["marketId"].endswith(instrument["currencies"][0]["name"]): base_symbol = instrument["marketId"][:-len(instrument["currencies"][0]["name"])] else: base_symbol = instrument["marketId"] market.base_exchange_rate = instrument['currencies'][0]['baseExchangeRate'] # "exchangeRate": 0.77 market.one_pip_means = float(instrument['onePipMeans'].split(' ')[0]) # "1 Index Point", "0.0001 USD/EUR" market.value_per_pip = float(instrument['valueOfOnePip']) market.contract_size = float(instrument['contractSize']) market.lot_size = float(instrument['lotSize']) market.set_base( base_symbol, base_symbol, decimal_place(market.one_pip_means)) if instrument['type'] in ('CURRENCIES'): pass # quote_precision = elif instrument['type'] in ('INDICES', 'COMMODITIES', 'SHARES', 'RATES', 'SECTORS'): pass # quote_precision = market.set_quote( instrument["currencies"][0]["name"], instrument["currencies"][0]['symbol'], decimal_place(market.one_pip_means)) # "forceOpenAllowed": true, # "stopsLimitsAllowed": true, # "controlledRiskAllowed": true, # "streamingPricesAvailable": true, if snapshot: market.is_open = snapshot["marketStatus"] == "TRADEABLE" market.bid = snapshot['bid'] market.ofr = snapshot['offer'] # "marginFactorUnit": "PERCENTAGE" not avalaible if market is down if instrument.get('marginFactor') and market.is_open: market.margin_factor = float(instrument['marginFactor']) margin_factor = instrument['marginFactor'] elif instrument.get('margin') and market.is_open: market.margin_factor = 0.1 / float(instrument['margin']) margin_factor = str(market.margin_factor) else: # we don't want this when market is down because it could overwrite the previous stored value margin_factor = None if instrument['unit'] == 'AMOUNT': market.unit_type = Market.UNIT_AMOUNT elif instrument['unit'] == 'CONTRACTS': market.unit_type = Market.UNIT_CONTRACTS elif instrument['unit'] == 'SHARES': market.unit_type = Market.UNIT_SHARES # BINARY OPT_* BUNGEE_* if instrument['type'] == 'CURRENCIES': market.market_type = Market.TYPE_CURRENCY elif instrument['type'] == 'INDICES': market.market_type = Market.TYPE_INDICE elif instrument['type'] == 'COMMODITIES': market.market_type = Market.TYPE_COMMODITY elif instrument['type'] == 'SHARES': market.market_type = Market.TYPE_STOCK elif instrument['type'] == 'RATES': market.market_type = Market.TYPE_RATE elif instrument['type'] == 'SECTORS': market.market_type = Market.TYPE_SECTOR market.trade = Market.TRADE_MARGIN | Market.TRADE_POSITION market.contract_type = Market.CONTRACT_CFD # take minDealSize as tick size market.set_size_limits(dealing_rules["minDealSize"]["value"], 0.0, dealing_rules["minDealSize"]["value"]) # @todo there is some limits in contract size market.set_notional_limits(0.0, 0.0, 0.0) # use one pip means for minimum and tick price size market.set_price_limits(market.one_pip_means, 0.0, market.one_pip_means) # commission for stocks @todo commission = "0.0" # store the last market info to be used for backtesting if not self._read_only: Database.inst().store_market_info((self.name, epic, market.symbol, market.market_type, market.unit_type, market.contract_type, # type market.trade, market.orders, # type market.base, market.base_display, market.base_precision, # base market.quote, market.quote_display, market.quote_precision, # quote market.expiry, int(market.last_update_time * 1000.0), # expiry, timestamp instrument['lotSize'], instrument['contractSize'], str(market.base_exchange_rate), instrument['valueOfOnePip'], instrument['onePipMeans'].split(' ')[0], margin_factor, dealing_rules["minDealSize"]["value"], "0.0", dealing_rules["minDealSize"]["value"], # size limits "0.0", "0.0", "0.0", # notional limits "0.0", "0.0", "0.0", # price limits "0.0", "0.0", commission, commission) # fees ) # print(market.symbol, market._size_limits, market._price_limits) # notify for strategy self.service.notify(Signal.SIGNAL_MARKET_INFO_DATA, self.name, (epic, market)) return market
def fetch_market(self, market_id): """ Fetch and cache it. It rarely changes, except for base exchange rate, so assume it once for all. @todo min/max/step/min_notional """ instrument = self.connector.ws.get_instrument(market_id) # funds = self.connector.ws.funds() # to get account base currency (if XBt or XBT) xbt_usd = self.connector.ws.get_instrument("XBTUSD") if instrument: # tickSize is the minimum price increment (0.5USD for XBTUSD) tradeable = instrument.get('state', 'Closed') == 'Open' update_time = self._parse_datetime(instrument.get('timestamp')).timestamp() symbol = instrument.get('symbol', '') base_symbol = instrument.get('rootSymbol', '') quote_symbol = symbol[-3:] # if funds['currency'] == 'XBt': # # XBt to XBT # ratio = 1.0 / 100000000.0 # if base_symbol == 'USD': # # USD is base then convert to XBT # ratio *= to_base_rate bid = instrument.get('bidPrice') ofr = instrument.get('askPrice') market = Market(market_id, symbol) # compute base precision from the tick size, example 0.05 => 2 base_precision = -math.floor(math.log10(instrument.get('tickSize', 1.0))) market.set_base(base_symbol, base_symbol, base_precision) market.set_quote(quote_symbol, quote_symbol) # base to XBT market.base_exchange_rate = 1.0 # base instrument base_market_id = "XBT" + quote_symbol base_market = self.connector.ws.get_instrument(base_market_id) if base_market_id != symbol and base_market: market.base_exchange_rate = base_market.get('lastPrice', 1.0) / instrument.get('lastPrice', 1.0) # @todo 'multiplier', 'riskStep', 'riskLimit' # limits min_notional = 1.0 # $ if quote_symbol != "USD" and base_market_id != "XBT": # any contract on futur XBT quote min_notional = 0.0001 # BCHXBT 'maxOrderQty': 100000000, 'maxPrice': 10, 'lotSize': 1, 'tickSize': 0.0001, # XBCUSD 'maxOrderQty': 10000000, 'maxPrice': 1000000, 'lotSize': 1, 'tickSize': 0.5, market.set_size_limits(instrument.get('tickSize', 1.0), instrument.get('maxOrderQty', 0.0), instrument.get('tickSize', 1.0)) market.set_notional_limits(min_notional, instrument.get('maxPrice', 0.0), 0.0) market.set_price_limits(0.0, 0.0, instrument.get('tickSize', 1.0)) # need to divided by account currency XBt = 100000000 market.margin_factor = instrument.get('initMargin', 1.0) # market.max_margin_factor = 1.0 / (instrument.get('riskLimit', 1.0) * ratio) # ex: 20000000000 for max leverage 200 # '-' if perpetual else match the regexp and keep the expiry part only expiry = BitMexWatcher.EXPIRY_RE.match(market_id) # or instrument.get(expiry') == '2018-12-28T12:00:00.000Z' for Z18 its 28 of month Z (december) and year 2018 if expiry is None: market.expiry = '-' else: market.expiry = expiry.group(2) + expiry.group(3) market.market_type = Market.TYPE_CRYPTO market.unit_type = Market.UNIT_CONTRACTS market.contract_type = Market.CONTRACT_CFD # and FUTUR market.trade = Market.TRADE_IND_MARGIN if bid is not None and ofr is not None: market.bid = bid market.ofr = ofr market.last_update_time = update_time market.lot_size = instrument.get('lotSize', 1.0) # ex: 1.0 for XBTUSD market.contract_size = 1.0 market.value_per_pip = 1.0 market.one_pip_means = instrument.get('tickSize', 1.0) # contract_size need to be updated as price changes # @todo this is wrong... same on update part above if quote_symbol == 'USD' and base_market_id == symbol: # XBTUSD... market.contract_size = 1.0 / instrument.get('lastPrice', 1.0) elif quote_symbol == 'USD' and base_market_id != symbol: # ETHUSD... market.contract_size = (0.001 * 0.01) * instrument.get('lastPrice', 1.0) elif base_market and base_market_id != symbol: # ADAZ18... market.contract_size = 1.0 / instrument.get('lastPrice', 1.0) market.value_per_pip = market.contract_size / instrument.get('lastPrice', 1.0) market.maker_fee = instrument.get('makerFee', 0.0) market.taker_fee = instrument.get('takerFee', 0.0) # store the last market info to be used for backtesting if not self._read_only: Database.inst().store_market_info((self.name, market_id, market.symbol, market.market_type, market.unit_type, market.contract_type, # type market.trade, market.orders, # type market.base, market.base_display, market.base_precision, # base market.quote, market.quote_display, market.quote_precision, # quote market.expiry, int(market.last_update_time * 1000.0), # expiry, timestamp str(market.lot_size), str(market.contract_size), str(market.base_exchange_rate), str(market.value_per_pip), str(market.one_pip_means), str(market.margin_factor), str(market.min_size), str(market.max_size), str(market.step_size), # size limits str(market.min_notional), str(market.max_notional), str(market.step_notional), # notional limits str(market.min_price), str(market.max_price), str(market.tick_price), # price limits str(market.maker_fee), str(market.taker_fee), str(market.maker_commission), str(market.taker_commission)) # fees ) # notify for strategy self.service.notify(Signal.SIGNAL_MARKET_INFO_DATA, self.name, (market_id, market)) return market
def process_market(self): # # insert market info # with self._mutex: mki = self._pending_market_info_insert self._pending_market_info_insert = [] if mki: try: cursor = self._db.cursor() for mi in mki: if mi[16] is None: # margin factor is unavailable when market is down, so use previous value if available cursor.execute("""SELECT margin_factor FROM market WHERE broker_id = '%s' AND market_id = '%s'""" % (mi[0], mi[1])) row = cursor.fetchone() if row: # replace by previous margin factor from the DB margin_factor = row[0] mi = list(mi) mi[16] = margin_factor else: mi[16] = "1.0" cursor.execute("""INSERT INTO market(broker_id, market_id, symbol, market_type, unit_type, contract_type, trade_type, orders, base, base_display, base_precision, quote, quote_display, quote_precision, expiry, timestamp, lot_size, contract_size, base_exchange_rate, value_per_pip, one_pip_means, margin_factor, min_size, max_size, step_size, min_notional, max_notional, step_notional, min_price, max_price, step_price, maker_fee, taker_fee, maker_commission, taker_commission) VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) ON CONFLICT (broker_id, market_id) DO UPDATE SET symbol = EXCLUDED.symbol, market_type = EXCLUDED.market_type, unit_type = EXCLUDED.unit_type, contract_type = EXCLUDED.contract_type, trade_type = EXCLUDED.trade_type, orders = EXCLUDED.orders, base = EXCLUDED.base, base_display = EXCLUDED.base_display, base_precision = EXCLUDED.base_precision, quote = EXCLUDED.quote, quote_display = EXCLUDED.quote_display, quote_precision = EXCLUDED.quote_precision, expiry = EXCLUDED.expiry, timestamp = EXCLUDED.timestamp, lot_size = EXCLUDED.lot_size, contract_size = EXCLUDED.contract_size, base_exchange_rate = EXCLUDED.base_exchange_rate, value_per_pip = EXCLUDED.value_per_pip, one_pip_means = EXCLUDED.one_pip_means, margin_factor = EXCLUDED.margin_factor, min_size = EXCLUDED.min_size, max_size = EXCLUDED.max_size, step_size = EXCLUDED.step_size, min_notional = EXCLUDED.min_notional, max_notional = EXCLUDED.max_notional, step_notional = EXCLUDED.step_notional, min_price = EXCLUDED.min_price, max_price = EXCLUDED.max_price, step_price = EXCLUDED.step_price, maker_fee = EXCLUDED.maker_fee, taker_fee = EXCLUDED.taker_fee, maker_commission = EXCLUDED.maker_commission, taker_commission = EXCLUDED.taker_commission""", (*mi,)) self._db.commit() except self.psycopg2.OperationalError as e: self.try_reconnect(e) # retry the next time with self._mutex: self._pending_market_info_insert = mki + self._pending_market_info_insert except Exception as e: self.on_error(e) # retry the next time with self._mutex: self._pending_market_info_insert = mki + self._pending_market_info_insert # # select market info # with self._mutex: mis = self._pending_market_info_select self._pending_market_info_select = [] if mis: try: cursor = self._db.cursor() for mi in mis: cursor.execute("""SELECT symbol, market_type, unit_type, contract_type, trade_type, orders, base, base_display, base_precision, quote, quote_display, quote_precision, expiry, timestamp, lot_size, contract_size, base_exchange_rate, value_per_pip, one_pip_means, margin_factor, min_size, max_size, step_size, min_notional, max_notional, step_notional, min_price, max_price, step_price, maker_fee, taker_fee, maker_commission, taker_commission FROM market WHERE broker_id = '%s' AND market_id = '%s'""" % ( mi[1], mi[2])) row = cursor.fetchone() if row: market_info = Market(mi[2], row[0]) market_info.is_open = True market_info.market_type = row[1] market_info.unit_type = row[2] market_info.contract_type = row[3] market_info.trade = row[4] market_info.orders = row[5] market_info.set_base(row[6], row[7], int(row[8])) market_info.set_quote(row[9], row[10], int(row[11])) market_info.expiry = row[12] market_info.last_update_time = row[13] * 0.001 market_info.lot_size = float(row[14]) market_info.contract_size = float(row[15]) market_info.base_exchange_rate = float(row[16]) market_info.value_per_pip = float(row[17]) market_info.one_pip_means = float(row[18]) if row[19] is not None or row[19] is not 'None': if row[19] == '-': # not defined mean 1.0 or no margin market_info.margin_factor = 1.0 else: market_info.margin_factor = float(row[19] or "1.0") market_info.set_size_limits(float(row[20]), float(row[21]), float(row[22])) market_info.set_notional_limits(float(row[23]), float(row[24]), float(row[25])) market_info.set_price_limits(float(row[26]), float(row[27]), float(row[28])) market_info.maker_fee = float(row[29]) market_info.taker_fee = float(row[30]) market_info.maker_commission = float(row[31]) market_info.taker_commission = float(row[32]) else: market_info = None # notify mi[0].notify(Signal.SIGNAL_MARKET_INFO_DATA, mi[1], (mi[2], market_info)) except self.psycopg2.OperationalError as e: self.try_reconnect(e) # retry the next time with self._mutex: self._pending_market_info_select = mis + self._pending_market_info_select except Exception as e: self.on_error(e) # retry the next time with self._mutex: self._pending_market_info_select = mis + self._pending_market_info_select # # select market list # with self._mutex: mls = self._pending_market_list_select self._pending_market_list_select = [] if mls: try: cursor = self._db.cursor() for m in mls: cursor.execute("""SELECT market_id, symbol, base, quote FROM market WHERE broker_id = '%s'""" % (m[1],)) rows = cursor.fetchall() market_list = [] for row in rows: market_list.append(row) # notify m[0].notify(Signal.SIGNAL_MARKET_LIST_DATA, m[1], market_list) except self.psycopg2.OperationalError as e: self.try_reconnect(e) # retry the next time with self._mutex: self._pending_market_list_select = mls + self._pending_market_list_select except Exception as e: self.on_error(e) # retry the next time with self._mutex: self._pending_market_list_select = mls + self._pending_market_list_select
def fetch_market(self, market_id): """ Fetch and cache it. It rarely changes. """ symbol = self._symbols_data.get(market_id) ticker = self._tickers_data.get(market_id) account = self._acount_data market = None if symbol and ticker and account: market = Market(symbol['symbol'], symbol['symbol']) market.is_open = symbol['status'] == "TRADING" market.expiry = '-' base_asset = symbol['baseAsset'] market.set_base(base_asset, base_asset, symbol['baseAssetPrecision']) quote_asset = symbol['quoteAsset'] market.set_quote(quote_asset, symbol.get('quoteAssetUnit', quote_asset), symbol['quotePrecision']) # tick size at the base asset precision market.one_pip_means = math.pow(10.0, -symbol['baseAssetPrecision']) market.value_per_pip = 1.0 market.contract_size = 1.0 market.lot_size = 1.0 # @todo add margin support market.margin_factor = 1.0 size_limits = ["1.0", "0.0", "1.0"] notional_limits = ["1.0", "0.0", "0.0"] price_limits = ["0.0", "0.0", "0.0"] # size min/max/step for afilter in symbol["filters"]: if afilter['filterType'] == "LOT_SIZE": size_limits = [ afilter['minQty'], afilter['maxQty'], afilter['stepSize'] ] elif afilter['filterType'] == "MIN_NOTIONAL": notional_limits[0] = afilter['minNotional'] elif afilter['filterType'] == "PRICE_FILTER": price_limits = [ afilter['minPrice'], afilter['maxPrice'], afilter['tickSize'] ] market.set_size_limits(float(size_limits[0]), float(size_limits[1]), float(size_limits[2])) market.set_price_limits(float(price_limits[0]), float(price_limits[1]), float(price_limits[2])) market.set_notional_limits(float(notional_limits[0]), 0.0, 0.0) market.unit_type = Market.UNIT_AMOUNT market.market_type = Market.TYPE_CRYPTO market.contract_type = Market.CONTRACT_SPOT market.trade = 0 if symbol.get('isSpotTradingAllowed', False): market.trade |= Market.TRADE_ASSET if symbol.get('isMarginTradingAllowed', False): market.trade |= Market.TRADE_IND_MARGIN # @todo orders capacities # symbol['orderTypes'] in ['LIMIT', 'LIMIT_MAKER', 'MARKET', 'STOP_LOSS_LIMIT', 'TAKE_PROFIT_LIMIT'] # market.orders = if symbol.get('ocoAllowed', False): market.orders |= Market.ORDER_ONE_CANCEL_OTHER market.maker_fee = account['makerCommission'] * 0.0001 market.taker_fee = account['takerCommission'] * 0.0001 # market.buyer_commission = account['buyerCommission'] # market.seller_commission = account['sellerCommission'] # only order book can give us bid/ofr market.bid = float(ticker['price']) market.ofr = float(ticker['price']) mid_price = float(ticker['price']) if quote_asset != self.BASE_QUOTE: if self._tickers_data.get(quote_asset + self.BASE_QUOTE): market.base_exchange_rate = float( self._tickers_data.get(quote_asset + self.BASE_QUOTE, {'price', '1.0'})['price']) elif self._tickers_data.get(self.BASE_QUOTE + quote_asset): market.base_exchange_rate = 1.0 / float( self._tickers_data.get(self.BASE_QUOTE + quote_asset, {'price', '1.0'})['price']) else: market.base_exchange_rate = 1.0 else: market.base_exchange_rate = 1.0 market.contract_size = 1.0 / mid_price market.value_per_pip = market.contract_size / mid_price # volume 24h # in client.get_ticker but cost is 40 for any symbols then wait it at all-tickets WS event # vol24_base = ticker24h('volume') # vol24_quote = ticker24h('quoteVolume') # notify for strategy self.service.notify(Signal.SIGNAL_MARKET_INFO_DATA, self.name, (market_id, market)) # store the last market info to be used for backtesting if not self._read_only: Database.inst().store_market_info(( self.name, market.market_id, market.symbol, market.market_type, market.unit_type, market.contract_type, # type market.trade, market.orders, # type market.base, market.base_display, market.base_precision, # base market.quote, market.quote_display, market.quote_precision, # quote market.expiry, int(market.last_update_time * 1000.0), # expiry, timestamp str(market.lot_size), str(market.contract_size), str(market.base_exchange_rate), str(market.value_per_pip), str(market.one_pip_means), '-', *size_limits, *notional_limits, *price_limits, str(market.maker_fee), str(market.taker_fee), str(market.maker_commission), str(market.taker_commission))) return market
def install_market_data(self, market_id, market_data): """ Install a market info data into the database. """ market = Market(market_id, market_data.get('symbol', market_id)) market.base_exchange_rate = market_data.get('base-exchange-rate', 1.0) market.one_pip_means = market_data.get('one-pip-means', 1.0) market.value_per_pip = market_data.get('value-per-pip', 1.0) market.contract_size = market_data.get('contract-size', 1.0) market.lot_size = market_data.get('lot-size', 1.0) market.expiry = market_data.get('expiry', '-') base = market_data.get('base', {}) market.set_base(base.get('symbol', 'USD'), base.get('display', '$'), base.get('precision', 2)) quote = market_data.get('quote', {}) market.set_base(quote.get('symbol', 'USD'), quote.get('display', '$'), quote.get('precision', 2)) market.is_open = True market.margin_factor = market_data.get('margin-factor', 1.0) if 'unit' in market_data: if market_data['unit'] == 'amount': market.unit_type = Market.UNIT_AMOUNT elif market_data['unit'] == 'contracts': market.unit_type = Market.UNIT_CONTRACTS elif market_data['unit'] == 'shares': market.unit_type = Market.UNIT_SHARES else: market.unit_type = Market.UNIT_CONTRACTS else: market.unit_type = Market.UNIT_CONTRACTS if 'type' in market_data: if market_data['type'] == 'currency': market.market_type = Market.TYPE_CURRENCY elif market_data['type'] == 'indice': market.market_type = Market.TYPE_INDICE elif market_data['type'] == 'commodity': market.market_type = Market.TYPE_COMMODITY elif market_data['type'] == 'stock': market.market_type = Market.TYPE_STOCK elif market_data['type'] == 'rate': market.market_type = Market.TYPE_RATE elif market_data['type'] == 'sector': market.market_type = Market.TYPE_SECTOR else: market.market_type = Market.TYPE_UNKNOWN else: market.market_type = Market.TYPE_UNKNOWN if 'contract' in market_data: if market_data['contract'] == 'spot': market.contract_type = Market.CONTRACT_SPOT elif market_data['contract'] == 'cfd': market.contract_type = Market.CONTRACT_CFD elif market_data['contract'] == 'futur': market.contract_type = Market.CONTRACT_FUTUR elif market_data['contract'] == 'option': market.contract_type = Market.CONTRACT_OPTION elif market_data['contract'] == 'warrant': market.contract_type = Market.CONTRACT_WARRANT elif market_data['contract'] == 'turbo': market.contract_type = Market.CONTRACT_TURBO else: market.contract_type = Market.CONTRACT_SPOT else: market.contract_type = Market.CONTRACT_SPOT market.trade = 0 if market_data.get('spot', False): market.trade |= Market.TRADE_BUY_SELL if market_data.get('margin', False): market.trade |= Market.TRADE_MARGIN if market_data.get('indivisible', False): market.trade |= Market.TRADE_IND_MARGIN if market_data.get('fifo', False): market.trade |= Market.TRADE_FIFO if market_data.get('position', False): market.trade |= Market.TRADE_POSITION orders = market_data.get( 'orders', ('market', 'limit', 'stop-market', 'stop-limit', 'take-profit-market', 'take-profit-limit')) if 'market' in orders: market.orders |= Market.ORDER_MARKET if 'limit' in orders: market.orders |= Market.ORDER_LIMIT if 'stop-market' in orders: market.orders |= Market.ORDER_STOP_MARKET if 'stop-limit' in orders: market.orders |= Market.ORDER_STOP_LIMIT if 'take-profit-market' in orders: market.orders |= Market.ORDER_TAKE_PROFIT_MARKET if 'take-profit-limit' in orders: market.orders |= Market.ORDER_TAKE_PROFIT_LIMIT if 'one-cancel-other' in orders: market.orders |= Market.ORDER_ONE_CANCEL_OTHER size_limits = market_data.get('size-limits', { 'min': 0.0, 'max': 0.0, 'step': 0.0 }) market.set_size_limits(size_limits.get('min', 0.0), size_limits.get('max', 0.0), size_limits.get('step', 0.0)) notional_limits = market_data.get('notional-limits', { 'min': 0.0, 'max': 0.0, 'step': 0.0 }) market.set_size_limits(notional_limits.get('min', 0.0), notional_limits.get('max', 0.0), notional_limits.get('step', 0.0)) price_limits = market_data.get('price-limits', { 'min': 0.0, 'max': 0.0, 'step': 0.0 }) market.set_size_limits(price_limits.get('min', 0.0), price_limits.get('max', 0.0), price_limits.get('step', 0.0)) # fees & commissions fees = market_data.get('fees', {}) market.maker_fee = fees.get('maker', 0.0) market.taker_fee = fees.get('taker', 0.0) commissions = market_data.get('commissions', {}) market.maker_commission = commissions.get('maker', 0.0) market.taker_commission = commissions.get('maker', 0.0) # store the last market info to be used for backtesting Database.inst().store_market_info(( self.name, market.market_id, market.symbol, market.market_type, market.unit_type, market.contract_type, # type market.trade, market.orders, # type market.base, market.base_display, market.base_precision, # base market.quote, market.quote_display, market.quote_precision, # quote market.expiry, int(market.last_update_time * 1000.0), # expiry, timestamp str(market.lot_size), str(market.contract_size), str(market.base_exchange_rate), str(market.value_per_pip), str(market.one_pip_means), str(market.margin_factor), str(market.min_size), str(market.max_size), str(market.step_size), # size limits str(market.min_notional), str(market.max_notional), str(market.step_notional), # notional limits str(market.min_price), str(market.max_price), str(market.tick_price), # price limits str(market.maker_fee), str(market.taker_fee), str(market.maker_commission), str(market.taker_commission)) # fees )
def fetch_market(self, market_id): """ Fetch and cache it. It rarely changes. """ instrument = self._instruments.get(market_id) market = None if instrument: market = Market(market_id, instrument['altname']) market.is_open = True market.expiry = '-' # "wsname":"XBT\/USD" # wsname = WebSocket pair name (if available) # pair_decimals = scaling decimal places for pair # lot_decimals = scaling decimal places for volume # lot_multiplier = amount to multiply lot volume by to get currency volume # "aclass_base":"currency" base_asset = instrument['base'] # XXBT market.set_base(base_asset, base_asset, instrument['pair_decimals']) # "aclass_quote":"currency" quote_asset = instrument['quote'] # ZUSD market.set_quote(quote_asset, quote_asset, instrument['lot_decimals']) # 8 # tick size at the base asset precision market.one_pip_means = math.pow(10.0, -instrument['pair_decimals']) # 1 market.value_per_pip = 1.0 market.contract_size = 1.0 market.lot_size = 1.0 # "lot":"unit", "lot_multiplier":1 # "margin_call":80, "margin_stop":40 # margin_call = margin call level # margin_stop = stop-out/liquidation margin level leverages = set(instrument.get('leverage_buy', [])) leverages.intersection(set(instrument.get('leverage_sell', []))) market.margin_factor = 1.0 / max(leverages) if len( leverages) > 0 else 1.0 market.set_leverages(leverages) size_limit = self._size_limits.get(instrument['altname'], {}) min_size = size_limit.get('min-size', 1.0) size_limits = [str(min_size), "0.0", str(min_size)] notional_limits = ["0.0", "0.0", "0.0"] price_limits = ["0.0", "0.0", "0.0"] market.set_size_limits(float(size_limits[0]), float(size_limits[1]), float(size_limits[2])) market.set_price_limits(float(price_limits[0]), float(price_limits[1]), float(price_limits[2])) market.set_notional_limits(float(notional_limits[0]), 0.0, 0.0) # "lot":"unit" market.unit_type = Market.UNIT_AMOUNT market.market_type = Market.TYPE_CRYPTO market.contract_type = Market.CONTRACT_SPOT market.trade = Market.TRADE_ASSET if leverages: market.trade |= Market.TRADE_MARGIN market.trade |= Market.TRADE_FIFO # orders capacities market.orders = Order.ORDER_LIMIT | Order.ORDER_MARKET | Order.ORDER_STOP | Order.ORDER_TAKE_PROFIT # @todo take the first but it might depends of the traded volume per 30 days, then request volume window to got it # "fees":[[0,0.26],[50000,0.24],[100000,0.22],[250000,0.2],[500000,0.18],[1000000,0.16],[2500000,0.14],[5000000,0.12],[10000000,0.1]], # "fees_maker":[[0,0.16],[50000,0.14],[100000,0.12],[250000,0.1],[500000,0.08],[1000000,0.06],[2500000,0.04],[5000000,0.02],[10000000,0]], fees = instrument.get('fees', []) fees_maker = instrument.get('fees_maker', []) if fees: market.taker_fee = round(fees[0][1] * 0.01, 6) if fees_maker: market.maker_fee = round(fees_maker[0][1] * 0.01, 6) if instrument.get('fee_volume_currency'): market.fee_currency = instrument['fee_volume_currency'] if quote_asset != self.BASE_QUOTE: # from XXBTZUSD / XXBTZEUR ... # @todo pass # if self._tickers_data.get(quote_asset+self.BASE_QUOTE): # market.base_exchange_rate = float(self._tickers_data.get(quote_asset+self.BASE_QUOTE, {'price', '1.0'})['price']) # elif self._tickers_data.get(self.BASE_QUOTE+quote_asset): # market.base_exchange_rate = 1.0 / float(self._tickers_data.get(self.BASE_QUOTE+quote_asset, {'price', '1.0'})['price']) # else: # market.base_exchange_rate = 1.0 else: market.base_exchange_rate = 1.0 # @todo contract_size # market.contract_size = 1.0 / mid_price # market.value_per_pip = market.contract_size / mid_price # volume 24h : not have here # notify for strategy self.service.notify(Signal.SIGNAL_MARKET_INFO_DATA, self.name, (market_id, market)) # store the last market info to be used for backtesting if not self._read_only: Database.inst().store_market_info(( self.name, market.market_id, market.symbol, market.market_type, market.unit_type, market.contract_type, # type market.trade, market.orders, # type market.base, market.base_display, market.base_precision, # base market.quote, market.quote_display, market.quote_precision, # quote market.expiry, int(market.last_update_time * 1000.0), # expiry, timestamp str(market.lot_size), str(market.contract_size), str(market.base_exchange_rate), str(market.value_per_pip), str(market.one_pip_means), '-', *size_limits, *notional_limits, *price_limits, str(market.maker_fee), str(market.taker_fee), str(market.maker_commission), str(market.taker_commission))) return market
def fetch_market(self, market_id): """ Fetch and cache it. It rarely changes. """ instrument = self._instruments.get(market_id) market = None if instrument: market = Market(market_id, instrument['altname']) market.is_open = True market.expiry = '-' # "wsname":"XBT\/USD" # wsname = WebSocket pair name (if available) # pair_decimals = scaling decimal places for pair # lot_decimals = scaling decimal places for volume # lot_multiplier = amount to multiply lot volume by to get currency volume # "aclass_base":"currency" base_asset = instrument['base'] # XXBT market.set_base(base_asset, base_asset, instrument['pair_decimals']) # "aclass_quote":"currency" quote_asset = instrument['quote'] # ZUSD market.set_quote(quote_asset, quote_asset, instrument['lot_decimals']) # 8 # tick size at the base asset precision market.one_pip_means = math.pow(10.0, -instrument['pair_decimals']) # 1 market.value_per_pip = 1.0 market.contract_size = 1.0 market.lot_size = 1.0 # "lot":"unit", "lot_multiplier":1 # "margin_call":80, "margin_stop":40 # margin_call = margin call level # margin_stop = stop-out/liquidation margin level leverages = set(instrument.get('leverage_buy', [])) leverages.intersection(set(instrument.get('leverage_sell', []))) market.margin_factor = 1.0 / max(leverages) market.set_leverages(leverages) size_limits = ["1.0", "0.0", "1.0"] notional_limits = ["1.0", "0.0", "0.0"] price_limits = ["0.0", "0.0", "0.0"] # size min/max/step @todo using lot_decimals / pair_decimals # for afilter in instrument["filters"]: # if afilter['filterType'] == "LOT_SIZE": # size_limits = [afilter['minQty'], afilter['maxQty'], afilter['stepSize']] # elif afilter['filterType'] == "MIN_NOTIONAL": # notional_limits[0] = afilter['minNotional'] # elif afilter['filterType'] == "PRICE_FILTER": # price_limits = [afilter['minPrice'], afilter['maxPrice'], afilter['tickSize']] # if float(size_limits[2]) < 1: # size_limits[2] = str(float(size_limits[2])) # * 10) market.set_size_limits(float(size_limits[0]), float(size_limits[1]), float(size_limits[2])) market.set_price_limits(float(price_limits[0]), float(price_limits[1]), float(price_limits[2])) market.set_notional_limits(float(notional_limits[0]), 0.0, 0.0) # "lot":"unit" market.unit_type = Market.UNIT_AMOUNT market.market_type = Market.TYPE_CRYPTO market.trade = Market.TRADE_ASSET market.contract_type = Market.CONTRACT_SPOT # @todo add a copy with market.trade = Market.TRADE_MARGIN market.contract_type = Market.CONTRACT_FUTUR # orders capacities market.orders = Order.ORDER_LIMIT | Order.ORDER_MARKET | Order.ORDER_STOP | Order.ORDER_TAKE_PROFIT # "fees":[[0,0.26],[50000,0.24],[100000,0.22],[250000,0.2],[500000,0.18],[1000000,0.16],[2500000,0.14],[5000000,0.12],[10000000,0.1]], # "fees_maker":[[0,0.16],[50000,0.14],[100000,0.12],[250000,0.1],[500000,0.08],[1000000,0.06],[2500000,0.04],[5000000,0.02],[10000000,0]], # market.maker_fee = account['makerCommission'] * 0.0001 # market.taker_fee = account['takerCommission'] * 0.0001 # 'fee_volume_currency': 'ZUSD' # fee_volume_currency = volume discount currency # if quote_asset != self.BASE_QUOTE: # if self._tickers_data.get(quote_asset+self.BASE_QUOTE): # market.base_exchange_rate = float(self._tickers_data.get(quote_asset+self.BASE_QUOTE, {'price', '1.0'})['price']) # elif self._tickers_data.get(self.BASE_QUOTE+quote_asset): # market.base_exchange_rate = 1.0 / float(self._tickers_data.get(self.BASE_QUOTE+quote_asset, {'price', '1.0'})['price']) # else: # market.base_exchange_rate = 1.0 # else: # market.base_exchange_rate = 1.0 # market.contract_size = 1.0 / mid_price # market.value_per_pip = market.contract_size / mid_price # volume 24h : not have here # store the last market info to be used for backtesting if not self._read_only: Database.inst().store_market_info(( self.name, market.market_id, market.symbol, market.market_type, market.unit_type, market.contract_type, # type market.trade, market.orders, # type market.base, market.base_display, market.base_precision, # base market.quote, market.quote_display, market.quote_precision, # quote market.expiry, int(market.last_update_time * 1000.0), # expiry, timestamp str(market.lot_size), str(market.contract_size), str(market.base_exchange_rate), str(market.value_per_pip), str(market.one_pip_means), '-', *size_limits, *notional_limits, *price_limits, str(market.maker_fee), str(market.taker_fee), str(market.maker_commission), str(market.taker_commission))) # notify for strategy self.service.notify(Signal.SIGNAL_MARKET_INFO_DATA, self.name, (market_id, market)) return market