use crate::{
mock_exchange_linear,
prelude::*,
test_fee_maker,
};
#[test]
#[tracing_test::traced_test]
fn submit_limit_sell_order_no_position() {
let mut exchange = mock_exchange_linear();
assert!(
exchange
.update_state(&Bba {
bid: QuoteCurrency::new(99, 0),
ask: QuoteCurrency::new(100, 0),
timestamp_exchange_ns: 0.into()
})
.unwrap()
.is_empty()
);
let limit_price = QuoteCurrency::new(100, 0);
let order = LimitOrder::new(Side::Sell, limit_price, BaseCurrency::new(9, 0)).unwrap();
exchange.submit_limit_order(order.clone()).unwrap();
assert_eq!(exchange.account().position(), &Position::default());
let meta = ExchangeOrderMeta::new(0.into(), 0.into());
let mut order = order.into_pending(meta);
let fee = QuoteCurrency::convert_from(order.remaining_quantity(), order.limit_price())
* *test_fee_maker().as_ref();
order.fill(order.remaining_quantity());
assert_eq!(
exchange
.update_state(&Trade {
price: QuoteCurrency::new(101, 0),
quantity: BaseCurrency::new(9, 0),
side: Side::Buy,
timestamp_exchange_ns: 1.into()
})
.unwrap(),
&vec![LimitOrderEvent::Fill(LimitOrderFill::FullyFilled {
filled_quantity: BaseCurrency::new(9, 0),
fee,
order_after_fill: order.into_filled(1.into())
})]
);
exchange
.update_state(&Bba {
bid: QuoteCurrency::new(101, 0),
ask: QuoteCurrency::new(102, 0),
timestamp_exchange_ns: 2.into(),
})
.unwrap();
let qty = BaseCurrency::new(9, 0);
let entry_price = QuoteCurrency::new(100, 0);
let fee0 = QuoteCurrency::convert_from(qty, entry_price) * *test_fee_maker().as_ref();
assert_eq!(
exchange.account().position().clone(),
Position::new(-qty, entry_price).unwrap()
);
assert_eq!(
exchange.account().balances(),
&Balances::builder()
.equity(QuoteCurrency::new(1_000, 0) - fee0)
.total_fees_paid(fee0)
.build()
);
assert_eq!(
exchange.account().position_margin(),
QuoteCurrency::new(900, 0)
);
assert!(exchange.account().order_margin().is_zero());
assert_eq!(
exchange.account().available_balance(),
QuoteCurrency::new(100, 0) - fee0
);
let order = LimitOrder::new(
Side::Buy,
QuoteCurrency::new(100, 0),
BaseCurrency::new(9, 0),
)
.unwrap();
exchange.submit_limit_order(order.clone()).unwrap();
let meta = ExchangeOrderMeta::new(1.into(), 2.into());
let mut order = order.into_pending(meta);
let fee1 = QuoteCurrency::convert_from(order.remaining_quantity(), order.limit_price())
* *test_fee_maker().as_ref();
order.fill(order.remaining_quantity());
assert_eq!(
exchange
.update_state(&Trade {
price: QuoteCurrency::new(99, 0),
quantity: BaseCurrency::new(9, 0),
side: Side::Sell,
timestamp_exchange_ns: 3.into(),
})
.unwrap(),
&vec![LimitOrderEvent::Fill(LimitOrderFill::FullyFilled {
filled_quantity: BaseCurrency::new(9, 0),
fee: fee1,
order_after_fill: order.into_filled(3.into()),
})]
);
assert_eq!(exchange.account().position(), &Position::default());
assert_eq!(
exchange.account().balances(),
&Balances::builder()
.equity(QuoteCurrency::new(1000, 0) - fee0 - fee1)
.total_fees_paid(fee0 + fee1)
.build()
);
assert_eq!(exchange.account().position_margin(), Zero::zero());
assert_eq!(exchange.account().order_margin(), Zero::zero());
}
#[test]
#[tracing_test::traced_test]
fn submit_limit_sell_order_no_position_max() {
let mut exchange = mock_exchange_linear();
assert!(
exchange
.update_state(&Bba {
bid: QuoteCurrency::new(99, 0),
ask: QuoteCurrency::new(100, 0),
timestamp_exchange_ns: 0.into()
})
.unwrap()
.is_empty()
);
let order = LimitOrder::new(
Side::Sell,
QuoteCurrency::new(100, 0),
BaseCurrency::new(5, 0),
)
.unwrap();
exchange.submit_limit_order(order.clone()).unwrap();
let order = LimitOrder::new(
Side::Sell,
QuoteCurrency::new(100, 0),
BaseCurrency::new(4, 0),
)
.unwrap();
exchange.submit_limit_order(order.clone()).unwrap();
let order = LimitOrder::new(
Side::Sell,
QuoteCurrency::new(100, 0),
BaseCurrency::new(1, 0),
)
.unwrap();
assert_eq!(
exchange.submit_limit_order(order),
Err(NotEnoughAvailableBalance.into())
);
let order = LimitOrder::new(
Side::Buy,
QuoteCurrency::new(99, 0),
BaseCurrency::new(5, 0),
)
.unwrap();
exchange.submit_limit_order(order.clone()).unwrap();
let order = LimitOrder::new(
Side::Buy,
QuoteCurrency::new(99, 0),
BaseCurrency::new(4, 0),
)
.unwrap();
exchange.submit_limit_order(order.clone()).unwrap();
let order = LimitOrder::new(
Side::Buy,
QuoteCurrency::new(99, 0),
BaseCurrency::new(2, 0),
)
.unwrap();
assert_eq!(
exchange.submit_limit_order(order.clone()),
Err(NotEnoughAvailableBalance.into())
);
}
#[test]
#[tracing_test::traced_test]
fn submit_limit_sell_order_below_bid() {
let mut exchange = mock_exchange_linear();
assert_eq!(
exchange
.update_state(&Bba {
bid: QuoteCurrency::new(99, 0),
ask: QuoteCurrency::new(100, 0),
timestamp_exchange_ns: 0.into()
})
.unwrap(),
&Vec::new()
);
let order = LimitOrder::new(
Side::Sell,
QuoteCurrency::new(99, 0),
BaseCurrency::new(9, 0),
)
.unwrap();
assert_eq!(
exchange.submit_limit_order(order),
Err(SubmitLimitOrderError::GoodTillCrossingRejectedOrder {
limit_price: QuoteCurrency::<i64, 5>::new(99, 0).to_string(),
away_market_quotation_price: QuoteCurrency::<i64, 5>::new(99, 0).to_string()
})
);
}
#[test]
#[tracing_test::traced_test]
fn submit_limit_sell_order_turnaround_long() {
}