def parse_forex_contract( details: ContractDetails, ) -> CurrencyPair: price_precision: int = _tick_size_to_precision(details.minTick) timestamp = time.time_ns() instrument_id = InstrumentId( symbol=Symbol(f"{details.contract.symbol}/{details.contract.currency}"), venue=Venue(details.contract.primaryExchange or details.contract.exchange), ) return CurrencyPair( instrument_id=instrument_id, native_symbol=Symbol(details.contract.localSymbol), base_currency=Currency.from_str(details.contract.currency), quote_currency=Currency.from_str(details.contract.symbol), price_precision=price_precision, size_precision=Quantity.from_int(1), price_increment=Price(details.minTick, price_precision), size_increment=Quantity(details.sizeMinTick or 1, 1), lot_size=None, max_quantity=None, min_quantity=None, max_notional=None, min_notional=None, max_price=None, min_price=None, margin_init=Decimal(0), margin_maint=Decimal(0), maker_fee=Decimal(0), taker_fee=Decimal(0), ts_event=timestamp, ts_init=timestamp, )
def test_currency_equality(self): # Arrange currency1 = Currency( code="AUD", precision=2, iso4217=36, name="Australian dollar", currency_type=CurrencyType.FIAT, ) currency2 = Currency( code="AUD", precision=2, iso4217=36, name="Australian dollar", currency_type=CurrencyType.FIAT, ) currency3 = Currency( code="GBP", precision=2, iso4217=826, name="British pound", currency_type=CurrencyType.FIAT, ) # Act, Assert assert currency1 == currency1 assert currency1 == currency2 assert currency1 != currency3
def default_fx_ccy(symbol: Symbol, leverage: Decimal=Decimal("50")) -> Instrument: """ Return a default FX currency pair instrument from the given symbol. Parameters ---------- symbol : Symbol The currency pair symbol. leverage : Decimal, optional The leverage for the instrument. Raises ------ ValueError If the symbol.code length is not in range [6, 7]. """ PyCondition.not_none(symbol, "symbol") PyCondition.in_range_int(len(symbol.code), 6, 7, "len(symbol)") base_currency = symbol.code[:3] quote_currency = symbol.code[-3:] # Check tick precision of quote currency if quote_currency == 'JPY': price_precision = 3 else: price_precision = 5 return Instrument( symbol=symbol, asset_class=AssetClass.FX, asset_type=AssetType.SPOT, base_currency=Currency.from_str(base_currency), quote_currency=Currency.from_str(quote_currency), settlement_currency=Currency.from_str(quote_currency), is_inverse=False, price_precision=price_precision, size_precision=0, tick_size=Decimal(f"{1 / 10 ** price_precision:.{price_precision}f}"), multiplier=Decimal("1"), leverage=leverage, lot_size=Quantity("1000"), max_quantity=Quantity("1e7"), min_quantity=Quantity("1000"), max_price=None, min_price=None, max_notional=Money(50000000.00, USD), min_notional=Money(1000.00, USD), margin_init=Decimal("0.03"), margin_maint=Decimal("0.03"), maker_fee=Decimal("0.00002"), taker_fee=Decimal("0.00002"), financing={}, timestamp=UNIX_EPOCH, )
def test_register_adds_currency_to_internal_currency_map(self): # Arrange, Act one_inch = Currency( code="1INCH", precision=8, iso4217=0, name="1INCH", currency_type=CurrencyType.CRYPTO, ) Currency.register(one_inch) result = Currency.from_str("1INCH") assert result == one_inch
def test_add_currency(self): # Arrange currency = Currency( code="1INCH", precision=8, iso4217=0, name="1INCH", currency_type=CurrencyType.CRYPTO, ) # Act self.cache.add_currency(currency) # Assert self.assertEqual(currency, Currency.from_str("1INCH"))
def test_register_when_overwrite_true_overwrites_internal_currency_map( self): # Arrange, Act another_aud = Currency( code="AUD", precision=8, iso4217=0, name="AUD", currency_type=CurrencyType.CRYPTO, ) Currency.register(another_aud, overwrite=False) result = Currency.from_str("AUD") assert result != another_aud
def test_is_crypto(self, string, expected): # Arrange # Act result = Currency.is_crypto(string) # Assert assert result == expected
def test_from_str(self, string, expected): # Arrange # Act result = Currency.from_str(string) # Assert assert result == expected
def test_is_fiat(self, string, expected): # Arrange # Act result = Currency.is_fiat(string) # Assert self.assertEqual(expected, result)
def _parse_futures_contract( self, instrument_id: InstrumentId, asset_class: AssetClass, details: ContractDetails, ) -> Future: price_precision: int = self._tick_size_to_precision(details.minTick) timestamp = time.time_ns() future = Future( instrument_id=instrument_id, local_symbol=Symbol(details.contract.localSymbol), asset_class=asset_class, currency=Currency.from_str(details.contract.currency), price_precision=price_precision, price_increment=Price(details.minTick, price_precision), multiplier=Quantity.from_int(int(details.contract.multiplier)), lot_size=Quantity.from_int(1), underlying=details.underSymbol, expiry_date=datetime.datetime.strptime( details.contract.lastTradeDateOrContractMonth, "%Y%m%d" ).date(), ts_event=timestamp, ts_init=timestamp, ) return future
def parse_future_contract( details: ContractDetails, ) -> Future: price_precision: int = _tick_size_to_precision(details.minTick) timestamp = time.time_ns() instrument_id = InstrumentId( symbol=Symbol(details.contract.localSymbol), venue=Venue(details.contract.primaryExchange or details.contract.exchange), ) return Future( instrument_id=instrument_id, native_symbol=Symbol(details.contract.localSymbol), asset_class=sec_type_to_asset_class(details.underSecType), currency=Currency.from_str(details.contract.currency), price_precision=price_precision, price_increment=Price(details.minTick, price_precision), multiplier=Quantity.from_int(int(details.contract.multiplier)), lot_size=Quantity.from_int(1), underlying=details.underSymbol, expiry_date=datetime.datetime.strptime( details.contract.lastTradeDateOrContractMonth, "%Y%m%d" ).date(), ts_event=timestamp, ts_init=timestamp, )
def parse_option_contract( details: ContractDetails, ) -> Option: price_precision: int = _tick_size_to_precision(details.minTick) timestamp = time.time_ns() instrument_id = InstrumentId( symbol=Symbol(details.contract.localSymbol.replace(" ", "")), venue=Venue(details.contract.primaryExchange or details.contract.exchange), ) asset_class = { "STK": AssetClass.EQUITY, }[details.underSecType] kind = { "C": OptionKind.CALL, "P": OptionKind.PUT, }[details.contract.right] return Option( instrument_id=instrument_id, native_symbol=Symbol(details.contract.localSymbol), asset_class=asset_class, currency=Currency.from_str(details.contract.currency), price_precision=price_precision, price_increment=Price(details.minTick, price_precision), multiplier=Quantity.from_int(int(details.contract.multiplier)), lot_size=Quantity.from_int(1), underlying=details.underSymbol, strike_price=Price.from_str(str(details.contract.strike)), expiry_date=datetime.datetime.strptime( details.contract.lastTradeDateOrContractMonth, "%Y%m%d" ).date(), kind=kind, ts_event=timestamp, ts_init=timestamp, )
def test_is_fiat(self, string, expected): # Arrange # Act result = Currency.is_fiat(string) # Assert assert expected == result
def betfair_account_to_account_state( account_detail, account_funds, event_id, updated_ns, timestamp_ns, account_id="001", ) -> AccountState: currency = Currency.from_str(account_detail["currencyCode"]) balance = float(account_funds["availableToBetBalance"]) locked = -float(account_funds["exposure"]) free = balance - locked return AccountState( account_id=AccountId(issuer=BETFAIR_VENUE.value, number=account_id), account_type=AccountType.CASH, base_currency=currency, reported=True, balances=[ AccountBalance( currency=currency, total=Money(balance, currency), locked=Money(locked, currency), free=Money(free, currency), ), ], info={"funds": account_funds, "detail": account_detail}, event_id=event_id, updated_ns=updated_ns, timestamp_ns=timestamp_ns, )
def parse_trade_report_http( account_id: AccountId, instrument_id: InstrumentId, data: BinanceFuturesAccountTrade, report_id: UUID4, ts_init: int, ) -> TradeReport: return TradeReport( account_id=account_id, instrument_id=instrument_id, venue_order_id=VenueOrderId(str(data.orderId)), venue_position_id=PositionId( f"{instrument_id}-{data.positionSide.value}"), trade_id=TradeId(str(data.id)), order_side=OrderSide[data.side.value], last_qty=Quantity.from_str(data.qty), last_px=Price.from_str(data.price), commission=Money(data.commission, Currency.from_str(data.commissionAsset)), liquidity_side=LiquiditySide.MAKER if data.maker else LiquiditySide.TAKER, report_id=report_id, ts_event=millis_to_nanos(data.time), ts_init=ts_init, )
def test_from_str(self, string, expected): # Arrange # Act result = Currency.from_str(string) # Assert self.assertEqual(expected, result)
def test_from_str_given_unknown_code_returns_none(self): # Arrange # Act result = Currency.from_str("SOME_CURRENCY") # Assert self.assertIsNone(result)
def betfair_account_to_account_state( account_detail, account_funds, event_id, ts_event, ts_init, account_id="001", ) -> AccountState: currency = Currency.from_str(account_detail["currencyCode"]) balance = float(account_funds["availableToBetBalance"]) locked = -float( account_funds["exposure"]) if account_funds["exposure"] else 0.0 free = balance - locked return AccountState( account_id=AccountId(issuer=BETFAIR_VENUE.value, number=account_id), account_type=AccountType.BETTING, base_currency=currency, reported=False, balances=[ AccountBalance( total=Money(balance, currency), locked=Money(locked, currency), free=Money(free, currency), ), ], margins=[], info={ "funds": account_funds, "detail": account_detail }, event_id=event_id, ts_event=ts_event, ts_init=ts_init, )
def _create_engine( self, config: BacktestEngineConfig, venue_configs: List[BacktestVenueConfig], data_configs: List[BacktestDataConfig], ): # Build the backtest engine engine = BacktestEngine(config=config) # Add instruments for config in data_configs: if is_nautilus_class(config.data_type): instruments = config.catalog().instruments( instrument_ids=config.instrument_id, as_nautilus=True) for instrument in instruments or []: engine.add_instrument(instrument) # Add venues for config in venue_configs: engine.add_venue( venue=Venue(config.name), venue_type=VenueType[config.venue_type], oms_type=OMSType[config.oms_type], account_type=AccountType[config.account_type], base_currency=Currency.from_str(config.base_currency), starting_balances=[ Money.from_str(m) for m in config.starting_balances ], book_type=BookTypeParser.from_str_py(config.book_type), ) return engine
def test_currency_equality(self): # Arrange currency1 = Currency("AUD", precision=2, currency_type=CurrencyType.FIAT) currency2 = Currency("AUD", precision=2, currency_type=CurrencyType.FIAT) currency3 = Currency("GBP", precision=2, currency_type=CurrencyType.FIAT) # Act # Assert self.assertTrue(currency1 == currency1) self.assertTrue(currency1 == currency2) self.assertTrue(currency1 != currency3)
def _news_event_from_dict(data): data.update( { "impact": getattr(NewsImpact, data["impact"]), "currency": Currency.from_str(data["currency"]), } ) return NewsEventData(**data)
def news_event_parser(df, state=None): for _, row in df.iterrows(): yield NewsEventData( name=str(row["Name"]), impact=getattr(NewsImpact, row["Impact"]), currency=Currency.from_str(row["Currency"]), ts_event=maybe_dt_to_unix_nanos(pd.Timestamp(row["Start"])), ts_init=maybe_dt_to_unix_nanos(pd.Timestamp(row["Start"])), )
def test_account_statement(betfair_client, uuid, clock): detail = betfair_client.account.get_account_details() funds = betfair_client.account.get_account_funds() result = betfair_account_to_account_state( account_detail=detail, account_funds=funds, event_id=uuid, timestamp_ns=clock.timestamp_ns(), ) expected = AccountState( AccountId(issuer="betfair", identifier="Testy-McTest"), [Money(1000.0, Currency.from_str("AUD"))], [Money(1000.0, Currency.from_str("AUD"))], [Money(-0.00, Currency.from_str("AUD"))], {"funds": funds, "detail": detail}, uuid, result.timestamp_ns, ) assert result == expected
def test_load_currencies_when_currencies_in_database_returns_expected(self): # Arrange aud = Currency.from_str("AUD") self.database.add_currency(aud) # Act result = self.database.load_currencies() # Assert assert result == {"AUD": aud}
def test_currency_hash(self): # Arrange currency = Currency("AUD", precision=2, currency_type=CurrencyType.FIAT) # Act # Assert self.assertEqual(int, type(hash(currency))) self.assertEqual(hash(currency), hash(currency))
def parse_account_margins_http(assets: List[BinanceFuturesAssetInfo]) -> List[MarginBalance]: margins: List[MarginBalance] = [] for a in assets: currency: Currency = Currency.from_str(a.asset) margin = MarginBalance( initial=Money(Decimal(a.initialMargin), currency), maintenance=Money(Decimal(a.maintMargin), currency), ) margins.append(margin) return margins
def test_str_repr(self): # Arrange currency = Currency("AUD", precision=2, currency_type=CurrencyType.FIAT) # Act # Assert self.assertEqual("AUD", str(currency)) self.assertEqual("Currency(code=AUD, precision=2, type=FIAT)", repr(currency))
def test_currency_hash(self): # Arrange currency = Currency( code="AUD", precision=2, iso4217=36, name="Australian dollar", currency_type=CurrencyType.FIAT, ) # Act, Assert assert isinstance(hash(currency), int) assert hash(currency) == hash(currency)
def test_default_fx_with_3_dp_returns_expected_instrument(self): # Arrange loader = TestInstrumentProvider() # Act instrument = loader.default_fx_ccy(Symbol("USD/JPY", Venue("SIM"))) # Assert self.assertEqual(Symbol("USD/JPY", Venue("SIM")), instrument.symbol) self.assertEqual(3, instrument.price_precision) self.assertEqual(Decimal("0.001"), instrument.tick_size) self.assertEqual( Currency(code='JPY', precision=2, currency_type=CurrencyType.FIAT), instrument.quote_currency)
def test_default_fx_with_5_dp_returns_expected_instrument(self): # Arrange loader = InstrumentLoader() # Act instrument = loader.default_fx_ccy(Symbol("AUD/USD", Venue('FXCM'))) # Assert self.assertEqual(Symbol("AUD/USD", Venue('FXCM')), instrument.symbol) self.assertEqual(5, instrument.price_precision) self.assertEqual(Decimal("0.00001"), instrument.tick_size) self.assertEqual( Currency(code='USD', precision=2, currency_type=CurrencyType.FIAT), instrument.quote_currency)