use crate::{
mock_exchange::MockTransactionAccounting, mock_exchange_linear, prelude::*, trade,
TEST_FEE_MAKER,
};
#[test]
#[tracing_test::traced_test]
fn submit_limit_sell_order_no_position() {
let mut exchange = mock_exchange_linear();
let mut accounting = MockTransactionAccounting::default();
let init_margin_req = exchange.config().contract_spec().init_margin_req();
assert!(exchange
.update_state(0.into(), &bba!(quote!(99), quote!(100)))
.unwrap()
.is_empty());
let limit_price = quote!(100);
let order = LimitOrder::new(Side::Sell, limit_price, base!(9)).unwrap();
exchange.submit_limit_order(order.clone()).unwrap();
assert_eq!(exchange.position(), &Position::Neutral,);
let ts = 0;
let meta = ExchangeOrderMeta::new(0.into(), ts.into());
let mut order = order.into_pending(meta);
let filled_order = order
.fill(order.remaining_quantity(), ts.into())
.expect("order is fully filled.");
let expected_order_update = LimitOrderUpdate::FullyFilled(filled_order);
assert_eq!(
exchange
.update_state(0.into(), &trade!(quote!(101), base!(9), Side::Buy))
.unwrap(),
vec![expected_order_update]
);
exchange
.update_state(0.into(), &bba!(quote!(101), quote!(102)))
.unwrap();
let qty = base!(9);
let entry_price = quote!(100);
let fee = qty.convert(entry_price) * TEST_FEE_MAKER;
assert_eq!(
exchange.position().clone(),
Position::Short(PositionInner::new(
qty,
entry_price,
&mut accounting,
init_margin_req,
fee,
))
);
assert_eq!(
exchange.user_balances(),
UserBalances {
available_wallet_balance: quote!(100),
position_margin: quote!(900),
order_margin: quote!(0)
}
);
assert_eq!(exchange.position().outstanding_fees(), quote!(0.18));
let order = LimitOrder::new(Side::Buy, quote!(100), base!(9)).unwrap();
exchange.submit_limit_order(order.clone()).unwrap();
let meta = ExchangeOrderMeta::new(1.into(), ts.into());
let mut order = order.into_pending(meta);
let filled_order = order
.fill(order.remaining_quantity(), ts.into())
.expect("order is fully filled.");
let expected_order_update = LimitOrderUpdate::FullyFilled(filled_order);
assert_eq!(
exchange
.update_state(0.into(), &trade!(quote!(99), base!(9), Side::Sell))
.unwrap(),
vec![expected_order_update]
);
assert_eq!(exchange.position(), &Position::Neutral);
assert_eq!(
exchange.user_balances(),
UserBalances {
available_wallet_balance: quote!(1000) - fee - fee,
position_margin: quote!(0),
order_margin: quote!(0)
}
);
}
#[test]
#[tracing_test::traced_test]
fn submit_limit_sell_order_no_position_max() {
let mut exchange = mock_exchange_linear();
assert!(exchange
.update_state(0.into(), &bba!(quote!(99), quote!(100)))
.unwrap()
.is_empty());
let order = LimitOrder::new(Side::Sell, quote!(100), base!(5)).unwrap();
exchange.submit_limit_order(order.clone()).unwrap();
let order = LimitOrder::new(Side::Sell, quote!(100), base!(4)).unwrap();
exchange.submit_limit_order(order.clone()).unwrap();
let order = LimitOrder::new(Side::Sell, quote!(100), base!(1)).unwrap();
exchange.submit_limit_order(order.clone()).unwrap();
let order = LimitOrder::new(Side::Buy, quote!(99), base!(5)).unwrap();
exchange.submit_limit_order(order.clone()).unwrap();
let order = LimitOrder::new(Side::Buy, quote!(99), base!(4)).unwrap();
exchange.submit_limit_order(order.clone()).unwrap();
let order = LimitOrder::new(Side::Buy, quote!(99), base!(2)).unwrap();
assert_eq!(
exchange.submit_limit_order(order.clone()),
Err(Error::RiskError(RiskError::NotEnoughAvailableBalance))
);
}
#[test]
#[tracing_test::traced_test]
fn submit_limit_sell_order_below_bid() {
let mut exchange = mock_exchange_linear();
assert_eq!(
exchange
.update_state(0.into(), &bba!(quote!(99), quote!(100)))
.unwrap(),
Vec::new()
);
let order = LimitOrder::new(Side::Sell, quote!(99), base!(9)).unwrap();
assert_eq!(
exchange.submit_limit_order(order),
Err(Error::OrderError(
OrderError::GoodTillCrossingRejectedOrder {
limit_price: quote!(99),
away_market_quotation_price: quote!(99)
}
))
);
}
#[test]
#[tracing_test::traced_test]
fn submit_limit_sell_order_turnaround_long() {
}