def test_run_ema_cross_with_tick_bar_spec(self):
        # Arrange
        strategy = EMACross(
            symbol=self.instrument.symbol,
            bar_spec=BarSpecification(250, BarAggregation.TICK,
                                      PriceType.LAST),
            trade_size=Decimal(100),
            fast_ema=10,
            slow_ema=20,
        )

        # Act
        self.engine.run(strategies=[strategy])

        # Assert
        self.assertEqual(39, strategy.fast_ema.count)
        self.assertEqual(19998, self.engine.iteration)
        self.assertEqual(Money('995991.41500000', USDT),
                         self.engine.portfolio.account(self.venue).balance())
示例#2
0
    def test_calculate_for_usdjpy(self):
        # Arrange
        sizer = FixedRiskSizer(
            InstrumentLoader.default_fx_ccy(TestStubs.symbol_usdjpy_fxcm()))
        equity = Money(1000000, USD)

        # Act
        result = sizer.calculate(
            equity,
            10,  # 0.1%
            Price("107.703"),
            Price("107.403"),
            exchange_rate=0.0093,
            units=1,
            unit_batch_size=1000,
        )

        # Assert
        self.assertEqual(Quantity(358000), result)
示例#3
0
    def test_comparisons_with_different_currencies_returns_false(
        self,
        value1,
        value2,
        expected1,
        expected2,
        expected3,
        expected4,
    ):
        # Arrange
        # Act
        result1 = Money(value1, USD) > Money(value2, BTC)
        result2 = Money(value1, USD) >= Money(value2, BTC)
        result3 = Money(value1, USD) <= Money(value2, BTC)
        result4 = Money(value1, USD) < Money(value2, BTC)

        # Assert
        assert expected1 == result1
        assert expected2 == result2
        assert expected3 == result3
        assert expected4 == result4
    def test_comparisons_with_various_values_returns_expected_result(
        self,
        value1,
        value2,
        expected1,
        expected2,
        expected3,
        expected4,
    ):
        # Arrange
        # Act
        result1 = Money(value1, USD) > Money(value2, USD)
        result2 = Money(value1, USD) >= Money(value2, USD)
        result3 = Money(value1, USD) <= Money(value2, USD)
        result4 = Money(value1, USD) < Money(value2, USD)

        # Assert
        self.assertEqual(expected1, result1)
        self.assertEqual(expected2, result2)
        self.assertEqual(expected3, result3)
        self.assertEqual(expected4, result4)
    def test_comparisons_with_different_currencies_returns_false(
        self,
        value1,
        value2,
        expected1,
        expected2,
        expected3,
        expected4,
    ):
        # Arrange
        # Act
        result1 = Money(value1, USD) > Money(value2, BTC)
        result2 = Money(value1, USD) >= Money(value2, BTC)
        result3 = Money(value1, USD) <= Money(value2, BTC)
        result4 = Money(value1, USD) < Money(value2, BTC)

        # Assert
        self.assertEqual(expected1, result1)
        self.assertEqual(expected2, result2)
        self.assertEqual(expected3, result3)
        self.assertEqual(expected4, result4)
    def test_apply_order_partially_filled_event_to_buy_limit_order(self):
        # Arrange
        order = self.order_factory.limit(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
            Price.from_str("1.00000"),
        )

        order.apply(TestStubs.event_order_submitted(order))
        order.apply(TestStubs.event_order_accepted(order))

        partially = OrderFilled(
            self.account_id,
            order.client_order_id,
            VenueOrderId("1"),
            ExecutionId("E-1"),
            PositionId("P-1"),
            StrategyId.null(),
            order.instrument_id,
            order.side,
            Quantity.from_int(50000),
            Price.from_str("0.999999"),
            AUDUSD_SIM.quote_currency,
            Money(0, USD),
            LiquiditySide.MAKER,
            1_000_000_000,
            uuid4(),
            1_000_000_000,
        )

        # Act
        order.apply(partially)

        # Assert
        self.assertEqual(OrderState.PARTIALLY_FILLED, order.state)
        self.assertEqual(Quantity.from_int(50000), order.filled_qty)
        self.assertEqual(Price.from_str("1.00000"), order.price)
        self.assertEqual(Decimal("0.999999"), order.avg_px)
        self.assertEqual(Decimal("-0.000001"), order.slippage)
        self.assertTrue(order.is_working)
        self.assertFalse(order.is_completed)
        self.assertEqual(1_000_000_000, order.ts_filled_ns)
    def test_run_ema_cross_with_tick_bar_spec(self):
        # Arrange
        strategy = EMACross(
            instrument_id=self.ethusdt.id,
            bar_spec=BarSpecification(250, BarAggregation.TICK,
                                      PriceType.LAST),
            trade_size=Decimal(100),
            fast_ema=10,
            slow_ema=20,
        )

        # Act
        self.engine.run(strategies=[strategy])

        # Assert
        self.assertEqual(279, strategy.fast_ema.count)
        self.assertEqual(69806, self.engine.iteration)
        self.assertEqual(Money("998873.43110000", USDT),
                         self.engine.portfolio.account(self.venue).balance())
    def btcusdt_future_binance(expiry: date = None) -> CryptoFuture:
        """
        Return the Binance BTCUSDT instrument for backtesting.

        Parameters
        ----------
        expiry : date, optional
            The expiry date for the contract.

        Returns
        -------
        CryptoFuture

        """
        if expiry is None:
            expiry = date(2022, 3, 25)
        return CryptoFuture(
            instrument_id=InstrumentId(
                symbol=Symbol(f"BTCUSDT_{expiry.strftime('%y%m%d')}"),
                venue=Venue("BINANCE"),
            ),
            native_symbol=Symbol("BTCUSDT"),
            underlying=BTC,
            quote_currency=USDT,
            settlement_currency=USDT,
            expiry_date=expiry,
            price_precision=2,
            size_precision=6,
            price_increment=Price(1e-02, precision=2),
            size_increment=Quantity(1e-06, precision=6),
            max_quantity=Quantity(9000, precision=6),
            min_quantity=Quantity(1e-06, precision=6),
            max_notional=None,
            min_notional=Money(10.00000000, USDT),
            max_price=Price(1000000, precision=2),
            min_price=Price(0.01, precision=2),
            margin_init=Decimal(0),
            margin_maint=Decimal(0),
            maker_fee=Decimal("0.001"),
            taker_fee=Decimal("0.001"),
            ts_event=0,
            ts_init=0,
        )
示例#9
0
 def event_betting_account_state(account_id=None) -> AccountState:
     return AccountState(
         account_id=account_id or TestStubs.account_id(),
         account_type=AccountType.BETTING,
         base_currency=GBP,
         reported=False,  # reported
         balances=[
             AccountBalance(
                 GBP,
                 Money(1_000, GBP),
                 Money(0, GBP),
                 Money(1_000, GBP),
             )
         ],
         info={},
         event_id=UUID4(),
         ts_event=0,
         ts_init=0,
     )
示例#10
0
 def event_margin_account_state(account_id=None) -> AccountState:
     return AccountState(
         account_id=account_id or TestStubs.account_id(),
         account_type=AccountType.MARGIN,
         base_currency=USD,
         reported=True,  # reported
         balances=[
             AccountBalance(
                 USD,
                 Money(1_000_000, USD),
                 Money(0, USD),
                 Money(1_000_000, USD),
             )
         ],
         info={},
         event_id=UUID4(),
         ts_event=0,
         ts_init=0,
     )
    def test_run_ema_cross_strategy(self):
        # Arrange
        strategy = EMACross(
            instrument_id=self.usdjpy.id,
            bar_spec=BarSpecification(15, BarAggregation.MINUTE,
                                      PriceType.BID),
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )

        # Act
        self.engine.run(strategies=[strategy])

        # Assert - Should return expected PnL
        self.assertEqual(2689, strategy.fast_ema.count)
        self.assertEqual(115043, self.engine.iteration)
        self.assertEqual(Money(997731.23, USD),
                         self.engine.portfolio.account(self.venue).balance())
示例#12
0
    def test_unrealized_pnl(self):
        # Arrange
        # Prepare market
        tick = TestStubs.quote_tick_3decimal(USDJPY_SIM.symbol)
        self.data_engine.process(tick)
        self.exchange.process_tick(tick)

        order_open = self.strategy.order_factory.market(
            USDJPY_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        # Act 1
        self.strategy.submit_order(order_open)

        reduce_quote = QuoteTick(
            USDJPY_SIM.symbol,
            Price("100.003"),
            Price("100.003"),
            Quantity(100000),
            Quantity(100000),
            UNIX_EPOCH,
        )

        self.exchange.process_tick(reduce_quote)
        self.portfolio.update_tick(reduce_quote)

        order_reduce = self.strategy.order_factory.market(
            USDJPY_SIM.symbol,
            OrderSide.SELL,
            Quantity(50000),
        )

        position_id = PositionId("B-USD/JPY-1")  # Generated by exchange

        # Act 2
        self.strategy.submit_order(order_reduce, position_id)

        # Assert
        position = self.exec_engine.cache.positions_open()[0]
        self.assertEqual(Money(500000.00, JPY),
                         position.unrealized_pnl(Price("100.003")))
    def test_update_orders_open_cash_account(self):
        # Arrange
        AccountFactory.register_calculated_account("BINANCE")

        account_id = AccountId("BINANCE", "000")
        state = AccountState(
            account_id=account_id,
            account_type=AccountType.CASH,
            base_currency=None,  # Multi-currency account
            reported=True,
            balances=[
                AccountBalance(
                    Money(10.00000000, BTC),
                    Money(0.00000000, BTC),
                    Money(10.00000000, BTC),
                ),
                AccountBalance(
                    Money(100000.00000000, USDT),
                    Money(0.00000000, USDT),
                    Money(100000.00000000, USDT),
                ),
            ],
            margins=[],
            info={},
            event_id=UUID4(),
            ts_event=0,
            ts_init=0,
        )

        self.portfolio.update_account(state)

        # Create open order
        order = self.order_factory.limit(
            BTCUSDT_BINANCE.id,
            OrderSide.BUY,
            Quantity.from_str("1.0"),
            Price.from_str("50000.00"),
        )

        self.cache.add_order(order, position_id=None)

        # Act: push order state to ACCEPTED
        self.exec_engine.process(
            TestEventStubs.order_submitted(order, account_id=account_id))
        self.exec_engine.process(
            TestEventStubs.order_accepted(order, account_id=account_id))

        # Assert
        assert self.portfolio.balances_locked(
            BINANCE)[USDT].as_decimal() == 50100
示例#14
0
    def event_order_filled(
        order,
        position_id=None,
        strategy_id=None,
        fill_price=None,
        filled_qty=None,
        leaves_qty=None,
        base_currency=USD,
        quote_currency=JPY,
        commission=0,
    ) -> OrderFilled:
        if position_id is None:
            position_id = PositionId(order.cl_ord_id.value.replace("P", "T"))
        if strategy_id is None:
            strategy_id = StrategyId("S", "NULL")
        if fill_price is None:
            fill_price = Price("1.00000")
        if filled_qty is None:
            filled_qty = order.quantity
        if leaves_qty is None:
            leaves_qty = Quantity()

        return OrderFilled(
            TestStubs.account_id(),
            order.cl_ord_id,
            OrderId("1"),
            ExecutionId(order.cl_ord_id.value.replace("O", "E")),
            position_id,
            strategy_id,
            order.symbol,
            order.side,
            filled_qty,
            leaves_qty,
            order.price if fill_price is None else fill_price,
            Money(commission, base_currency),
            LiquiditySide.TAKER,
            base_currency,  # Stub event
            quote_currency,  # Stub event
            UNIX_EPOCH,
            uuid4(),
            UNIX_EPOCH,
        )
    def test_run_ema_cross_with_minute_bar_spec(self):
        # Arrange
        strategy = EMACross(
            instrument_id=self.gbpusd.id,
            bar_spec=BarSpecification(5, BarAggregation.MINUTE, PriceType.MID),
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )

        # Act
        self.engine.run(strategies=[strategy])

        # Assert
        self.assertEqual(8353, strategy.fast_ema.count)
        self.assertEqual(120467, self.engine.iteration)
        self.assertEqual(
            Money(947226.84, GBP),
            self.engine.portfolio.account(self.venue).balance_total(GBP),
        )
    def test_run_ema_cross_with_tick_bar_spec(self):
        # Arrange
        strategy = EMACross(
            instrument_id=self.audusd.id,
            bar_spec=BarSpecification(100, BarAggregation.TICK, PriceType.MID),
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )

        # Act
        self.engine.run(strategies=[strategy])

        # Assert
        self.assertEqual(999, strategy.fast_ema.count)
        self.assertEqual(99999, self.engine.iteration)
        self.assertEqual(
            Money(995431.92, AUD),
            self.engine.portfolio.account(self.venue).balance_total(AUD),
        )
示例#17
0
def test_data_catalog_backtest_data_filtered(catalog):
    instruments = catalog.instruments(as_nautilus=True)
    engine = BacktestEngine(bypass_logging=True)
    engine = catalog.setup_engine(
        engine=engine,
        instruments=[instruments[1]],
        start_timestamp=1576869877788000000,
    )
    engine.add_venue(
        venue=BETFAIR_VENUE,
        venue_type=VenueType.EXCHANGE,
        account_type=AccountType.CASH,
        base_currency=GBP,
        oms_type=OMSType.NETTING,
        starting_balances=[Money(10000, GBP)],
        order_book_level=BookLevel.L2,
    )
    engine.run()
    # Total events 1045
    assert engine.iteration == 530
示例#18
0
    def test_run_ema_cross_strategy(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.usdjpy.id),
            bar_type="USD/JPY.SIM-15-MINUTE-BID-INTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert - Should return expected PnL
        assert strategy.fast_ema.count == 2689
        assert self.engine.iteration == 115044
        assert self.engine.portfolio.account(
            self.venue).balance_total(USD) == Money(992811.26, USD)
示例#19
0
    def test_run_ema_cross_with_minute_bar_spec(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id="AUD/USD.SIM",
            bar_type="AUD/USD.SIM-1-MINUTE-MID-INTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert
        assert strategy.fast_ema.count == 1771
        assert self.engine.iteration == 100000
        assert self.engine.portfolio.account(
            self.venue).balance_total(AUD) == Money(987920.04, AUD)
示例#20
0
    def test_run_ema_cross_with_tick_bar_spec(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.audusd.id),
            bar_type="AUD/USD.SIM-100-TICK-MID-INTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert
        assert strategy.fast_ema.count == 1000
        assert self.engine.iteration == 100000
        assert self.engine.portfolio.account(
            self.venue).balance_total(AUD) == Money(994441.60, AUD)
示例#21
0
    def test_run_ema_cross_with_minute_bar_spec(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.gbpusd.id),
            bar_type="GBP/USD.SIM-5-MINUTE-MID-INTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert
        assert strategy.fast_ema.count == 8353
        assert self.engine.iteration == 120468
        assert self.engine.portfolio.account(
            self.venue).balance_total(GBP) == Money(931346.81, GBP)
    def test_run_ema_cross_with_tick_bar_spec(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.ethusdt.id),
            bar_type="ETH/USDT.BINANCE-250-TICK-LAST-INTERNAL",
            trade_size=Decimal(100),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert
        assert strategy.fast_ema.count == 279
        assert self.engine.iteration == 69806
        assert self.engine.portfolio.account(
            self.venue).balance_total(USDT) == Money(998450.62196820, USDT)
示例#23
0
    def ethusdt_binance() -> Instrument:
        """
        Return the Binance ETH/USDT instrument for backtesting.

        Returns
        -------
        Instrument

        """
        instrument_id = InstrumentId(
            symbol=Symbol("ETH/USDT"),
            venue=Venue("BINANCE"),
        )

        return Instrument(
            instrument_id=instrument_id,
            asset_class=AssetClass.CRYPTO,
            asset_type=AssetType.SPOT,
            base_currency=ETH,
            quote_currency=USDT,
            settlement_currency=USDT,
            is_inverse=False,
            price_precision=2,
            size_precision=5,
            tick_size=Decimal("0.01"),
            multiplier=Decimal("1"),
            leverage=Decimal("1"),
            lot_size=Quantity("1"),
            max_quantity=Quantity("9000"),
            min_quantity=Quantity("1e-05"),
            max_notional=None,
            min_notional=Money("10.00000000", USDT),
            max_price=Price("1000000.0"),
            min_price=Price("0.01"),
            margin_init=Decimal("1.00"),
            margin_maint=Decimal("0.35"),
            maker_fee=Decimal("0.0001"),
            taker_fee=Decimal("0.0001"),
            financing={},
            timestamp=UNIX_EPOCH,
        )
示例#24
0
    def test_submit_limit_order_aggressive_multiple_levels(self):
        # Arrange: Prepare market
        self.cache.add_instrument(USDJPY_SIM)

        quote = QuoteTick(
            instrument_id=USDJPY_SIM.id,
            bid=Price.from_str("110.000"),
            ask=Price.from_str("110.010"),
            bid_size=Quantity.from_int(1500000),
            ask_size=Quantity.from_int(1500000),
            ts_event=0,
            ts_init=0,
        )
        self.data_engine.process(quote)
        snapshot = TestDataStubs.order_book_snapshot(
            instrument_id=USDJPY_SIM.id,
            bid_volume=1000,
            ask_volume=1000,
        )
        self.data_engine.process(snapshot)
        self.exchange.process_order_book(snapshot)

        # Create order
        order = self.strategy.order_factory.limit(
            instrument_id=USDJPY_SIM.id,
            order_side=OrderSide.BUY,
            quantity=Quantity.from_int(2000),
            price=Price.from_int(20),
            post_only=False,
        )

        # Act
        self.strategy.submit_order(order)
        self.exchange.process(0)

        # Assert
        assert order.status == OrderStatus.FILLED
        assert order.filled_qty == Decimal("2000.0")  # No slippage
        assert order.avg_px == Decimal("15.33333333333333333333333333")
        assert self.exchange.get_account().balance_total(USD) == Money(
            999999.96, USD)
    def setUp(self):
        # Fixture Setup
        self.engine = BacktestEngine(bypass_logging=True)

        self.venue = Venue("BINANCE")
        self.instrument = TestInstrumentProvider.btcusdt_binance()

        self.engine.add_instrument(self.instrument)
        self.engine.add_trade_ticks(self.instrument.id,
                                    TestDataProvider.tardis_trades())
        self.engine.add_quote_ticks(self.instrument.id,
                                    TestDataProvider.tardis_quotes())
        self.engine.add_venue(
            venue=self.venue,
            venue_type=VenueType.EXCHANGE,
            oms_type=OMSType.NETTING,
            account_type=AccountType.CASH,
            base_currency=None,  # Multi-currency account
            starting_balances=[Money(1_000_000, USDT),
                               Money(10, BTC)],
        )
    def test_calculate_pnls_partially_closed(self):
        # Arrange
        event = self._make_account_state(starting_balance=1000.0)
        account = BettingAccount(event)
        fill1 = self._make_fill(price="0.50", volume=100, side="BUY")
        fill2 = self._make_fill(price="0.80", volume=100, side="SELL")

        position = Position(self.instrument, fill1)
        position.apply(fill2)

        # Act
        result = account.calculate_pnls(
            instrument=self.instrument,
            position=position,
            fill=fill2,
        )

        # Assert
        # TODO - this should really be 75 GBP given the position (but we are currently not using position?)
        # assert result == [Money("75.00", GBP)]
        assert result == [Money("80.00", GBP)]
示例#27
0
    def test_run_ema_cross_with_minute_bar_spec(self):
        # Arrange
        config = EMACrossConfig(
            instrument_id=str(self.gbpusd.id),
            bar_type="GBP/USD.SIM-1-MINUTE-BID-EXTERNAL",
            trade_size=Decimal(1_000_000),
            fast_ema=10,
            slow_ema=20,
        )
        strategy = EMACross(config=config)
        self.engine.add_strategy(strategy)

        # Act
        self.engine.run()

        # Assert
        assert strategy.fast_ema.count == 30117
        assert self.engine.iteration == 60234
        ending_balance = self.engine.portfolio.account(
            self.venue).balance_total(USD)
        assert ending_balance == Money(1016188.45, USD)
    def test_margin_available_for_single_asset_account(self):
        # Arrange
        event = AccountState(
            account_id=AccountId("SIM", "001"),
            account_type=AccountType.CASH,
            base_currency=USD,
            reported=True,
            balances=[
                AccountBalance(
                    USD,
                    Money(100000.00, USD),
                    Money(0.00, USD),
                    Money(100000.00, USD),
                ),
            ],
            info={},
            event_id=uuid4(),
            ts_updated_ns=0,
            timestamp_ns=0,
        )

        account = Account(event)

        # Wire up account to portfolio
        account.register_portfolio(self.portfolio)
        self.portfolio.register_account(account)

        # Act
        result1 = account.margin_available()
        account.update_initial_margin(Money(500.00, USD))
        result2 = account.margin_available()
        account.update_maint_margin(Money(1000.00, USD))
        result3 = account.margin_available()

        # Assert
        self.assertEqual(Money(100000.00, USD), result1)
        self.assertEqual(Money(99500.00, USD), result2)
        self.assertEqual(Money(98500.00, USD), result3)
    def test_unrealized_pnl_when_insufficient_data_for_xrate_returns_none(
            self):
        # Arrange
        state = AccountState(
            account_id=AccountId("BITMEX", "01234"),
            balances=[Money("10.00000000", BTC),
                      Money("10.00000000", ETH)],
            balances_free=[
                Money("10.00000000", BTC),
                Money("10.00000000", ETH)
            ],
            balances_locked=[
                Money("0.00000000", BTC),
                Money("0.00000000", ETH)
            ],
            info={},
            event_id=uuid4(),
            event_timestamp=UNIX_EPOCH,
        )

        account = Account(state)

        self.portfolio.register_account(account)
        order = self.order_factory.market(
            ETHUSD_BITMEX.symbol,
            OrderSide.BUY,
            Quantity(100),
        )

        fill = TestStubs.event_order_filled(
            order=order,
            instrument=ETHUSD_BITMEX,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("376.05"),
        )

        position = Position(fill)

        self.portfolio.update_position(
            TestStubs.event_position_opened(position))

        # Act
        result = self.portfolio.unrealized_pnls(BITMEX)

        # # Assert
        self.assertIsNone(result)
    def test_update_maint_margin(self):
        # Arrange
        event = AccountState(
            account_id=AccountId("SIM", "001"),
            account_type=AccountType.CASH,
            base_currency=None,  # Multi-currency
            reported=True,
            balances=[
                AccountBalance(
                    BTC,
                    Money(10.00000000, BTC),
                    Money(0.00000000, BTC),
                    Money(10.00000000, BTC),
                ),
                AccountBalance(
                    ETH,
                    Money(20.00000000, ETH),
                    Money(0.00000000, ETH),
                    Money(20.00000000, ETH),
                ),
            ],
            info={},  # No default currency set
            event_id=uuid4(),
            ts_updated_ns=0,
            timestamp_ns=0,
        )

        # Act
        account = Account(event)

        # Wire up account to portfolio
        account.register_portfolio(self.portfolio)
        self.portfolio.register_account(account)

        margin = Money(0.00050000, BTC)

        # Act
        account.update_maint_margin(margin)

        # Assert
        self.assertEqual(margin, account.maint_margin(BTC))
        self.assertEqual({BTC: margin}, account.maint_margins())