//! Test if a pure limit order strategy works correctly use lfest::{ mock_exchange_linear, mock_exchange_linear_with_account_tracker, prelude::*, trade, MockTransactionAccounting, }; #[test] #[tracing_test::traced_test] fn limit_orders_only() { let mut exchange = mock_exchange_linear_with_account_tracker(quote!(1000)); let mut accounting = MockTransactionAccounting::default(); let init_margin_req = exchange.config().contract_spec().init_margin_req(); let fee_maker = exchange.config().contract_spec().fee_maker(); let bid = quote!(100); let ask = quote!(101); let exec_orders = exchange.update_state(0.into(), &bba!(bid, ask)).unwrap(); assert_eq!(exec_orders.len(), 0); let qty = base!(9.9); let fee0 = qty.convert(bid) * fee_maker; let o = LimitOrder::new(Side::Buy, bid, qty).unwrap(); exchange.submit_limit_order(o).unwrap(); assert_eq!( exchange.user_balances(), UserBalances { available_wallet_balance: quote!(10), position_margin: quote!(0), order_margin: quote!(990), } ); assert_eq!(exchange.position().outstanding_fees(), quote!(0)); assert_eq!(exchange.account_tracker().num_submitted_limit_orders(), 1); assert_eq!(exchange.account_tracker().num_cancelled_limit_orders(), 0); assert_eq!( exchange.account_tracker().num_fully_filled_limit_orders(), 0 ); assert_eq!(exchange.account_tracker().num_submitted_market_orders(), 0); assert_eq!(exchange.account_tracker().num_filled_market_orders(), 0); assert_eq!(exchange.account_tracker().buy_volume(), quote!(0)); assert_eq!(exchange.account_tracker().sell_volume(), quote!(0)); assert_eq!(exchange.fees_paid(), quote!(0)); let order_updates = exchange .update_state(1.into(), &trade!(quote!(99), base!(10), Side::Sell)) .unwrap(); assert_eq!(order_updates.len(), 1); let order_updates = exchange .update_state(1.into(), &bba!(quote!(98), quote!(99))) .unwrap(); assert!(order_updates.is_empty()); assert_eq!( exchange.position().clone(), Position::Long(PositionInner::new( qty, quote!(100), &mut accounting, init_margin_req, fee0 )) ); assert_eq!( exchange .position() .unrealized_pnl(exchange.market_state().bid(), exchange.market_state().ask()), quote!(-19.8) ); assert_eq!( exchange.user_balances(), UserBalances { available_wallet_balance: quote!(10), position_margin: quote!(990), order_margin: quote!(0) } ); assert_eq!(exchange.position().outstanding_fees(), fee0); assert_eq!(exchange.account_tracker().num_submitted_limit_orders(), 1); assert_eq!(exchange.account_tracker().num_cancelled_limit_orders(), 0); assert_eq!( exchange.account_tracker().num_fully_filled_limit_orders(), 1 ); assert_eq!(exchange.account_tracker().num_submitted_market_orders(), 0); assert_eq!(exchange.account_tracker().num_filled_market_orders(), 0); assert_eq!(exchange.account_tracker().buy_volume(), quote!(990)); assert_eq!(exchange.account_tracker().sell_volume(), quote!(0)); let sell_price = quote!(105); let fee1 = qty.convert(sell_price) * fee_maker; let o = LimitOrder::new(Side::Sell, sell_price, qty).unwrap(); exchange.submit_limit_order(o).unwrap(); let order_updates = exchange .update_state(2.into(), &trade!(quote!(106), base!(10), Side::Buy)) .unwrap(); assert!(!order_updates.is_empty()); assert_eq!( exchange.user_balances(), UserBalances { available_wallet_balance: quote!(1049.5) - fee0 - fee1, position_margin: quote!(0), order_margin: quote!(0) } ); let order_updates = exchange .update_state(2.into(), &bba!(quote!(106), quote!(107))) .unwrap(); assert!(order_updates.is_empty()); assert_eq!(exchange.position(), &Position::Neutral); assert_eq!( exchange.user_balances(), UserBalances { available_wallet_balance: quote!(1049.5) - quote!(0.198) - quote!(0.2079), position_margin: quote!(0), order_margin: quote!(0) } ); assert_eq!(exchange.account_tracker().num_submitted_limit_orders(), 2); assert_eq!(exchange.account_tracker().num_cancelled_limit_orders(), 0); assert_eq!( exchange.account_tracker().num_fully_filled_limit_orders(), 2 ); assert_eq!(exchange.account_tracker().num_submitted_market_orders(), 0); assert_eq!(exchange.account_tracker().num_filled_market_orders(), 0); assert_eq!(exchange.account_tracker().buy_volume(), quote!(990)); assert_eq!(exchange.account_tracker().sell_volume(), quote!(1039.5)); assert_eq!(exchange.fees_paid(), quote!(0.4059)); } #[test] #[tracing_test::traced_test] fn limit_orders_2() { let mut exchange = mock_exchange_linear(); let exec_orders = exchange .update_state( 0.into(), &Bba { bid: quote!(100), ask: quote!(101), }, ) .unwrap(); assert!(exec_orders.is_empty()); let o = LimitOrder::new(Side::Sell, quote!(101), base!(0.75)).unwrap(); exchange.submit_limit_order(o).unwrap(); let o = LimitOrder::new(Side::Buy, quote!(100), base!(0.5)).unwrap(); exchange.submit_limit_order(o).unwrap(); let exec_orders = exchange .update_state(1.into(), &trade!(quote!(98), base!(2), Side::Sell)) .unwrap(); let _ = exchange .update_state(1.into(), &bba!(quote!(98), quote!(99))) .unwrap(); assert_eq!(exec_orders.len(), 1); }