mango-explorer/tests/marketmaking/test_toleranceorderreconcil...

229 lines
10 KiB
Python

import mango
from decimal import Decimal
from mango.marketmaking.toleranceorderreconciler import ToleranceOrderReconciler
from ..fakes import fake_model_state
def test_buy_does_not_match_sell() -> None:
actual = ToleranceOrderReconciler(Decimal(1), Decimal(1))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.SELL, price=Decimal(1), quantity=Decimal(10))
assert not actual.is_within_tolderance(existing, desired)
def test_exact_match_with_small_tolerance_matches() -> None:
actual = ToleranceOrderReconciler(Decimal("0.001"), Decimal("0.001"))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
assert actual.is_within_tolderance(existing, desired)
def test_exact_match_with_zero_tolerance_matches() -> None:
actual = ToleranceOrderReconciler(Decimal(0), Decimal(0))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
assert actual.is_within_tolderance(existing, desired)
def test_quantity_within_positive_tolerance_matches() -> None:
actual = ToleranceOrderReconciler(Decimal(0), Decimal("0.001"))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal("10.009"))
assert actual.is_within_tolderance(existing, desired)
def test_quantity_positive_tolerance_boundary_matches() -> None:
actual = ToleranceOrderReconciler(Decimal(0), Decimal("0.001"))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal("10.01"))
assert actual.is_within_tolderance(existing, desired)
def test_quantity_outside_positive_tolerance_no_match() -> None:
actual = ToleranceOrderReconciler(Decimal(0), Decimal("0.001"))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal("10.011"))
assert not actual.is_within_tolderance(existing, desired)
def test_quantity_within_negative_tolerance_matches() -> None:
actual = ToleranceOrderReconciler(Decimal(0), Decimal("0.001"))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal("9.991"))
assert actual.is_within_tolderance(existing, desired)
def test_quantity_negative_tolerance_boundary_matches() -> None:
actual = ToleranceOrderReconciler(Decimal(0), Decimal("0.001"))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal("9.99"))
assert actual.is_within_tolderance(existing, desired)
def test_quantity_outside_negative_tolerance_no_match() -> None:
actual = ToleranceOrderReconciler(Decimal(0), Decimal("0.001"))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal("9.989"))
assert not actual.is_within_tolderance(existing, desired)
def test_price_within_positive_tolerance_matches() -> None:
actual = ToleranceOrderReconciler(Decimal("0.001"), Decimal(0))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal("1.0009"), quantity=Decimal(10))
assert actual.is_within_tolderance(existing, desired)
def test_price_positive_tolerance_boundary_matches() -> None:
actual = ToleranceOrderReconciler(Decimal("0.001"), Decimal(0))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal("1.001"), quantity=Decimal(10))
assert actual.is_within_tolderance(existing, desired)
def test_price_outside_positive_tolerance_no_match() -> None:
actual = ToleranceOrderReconciler(Decimal("0.001"), Decimal(0))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal("1.0011"), quantity=Decimal(10))
assert not actual.is_within_tolderance(existing, desired)
def test_price_within_negative_tolerance_matches() -> None:
actual = ToleranceOrderReconciler(Decimal("0.001"), Decimal(0))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal("0.9991"), quantity=Decimal(10))
assert actual.is_within_tolderance(existing, desired)
def test_price_negative_tolerance_boundary_matches() -> None:
actual = ToleranceOrderReconciler(Decimal("0.001"), Decimal(0))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal("0.999"), quantity=Decimal(10))
assert actual.is_within_tolderance(existing, desired)
def test_price_outside_negative_tolerance_no_match() -> None:
actual = ToleranceOrderReconciler(Decimal("0.001"), Decimal(0))
existing = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(1), quantity=Decimal(10))
desired = mango.Order.from_basic_info(mango.Side.BUY, price=Decimal("0.9989"), quantity=Decimal(10))
assert not actual.is_within_tolderance(existing, desired)
def test_reconcile_no_acceptable_orders() -> None:
existing = [
mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(99), quantity=Decimal(10)),
mango.Order.from_basic_info(mango.Side.SELL, price=Decimal(101), quantity=Decimal(10))
]
desired = [
mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(100), quantity=Decimal(10)),
mango.Order.from_basic_info(mango.Side.SELL, price=Decimal(102), quantity=Decimal(10))
]
model_state = fake_model_state()
actual = ToleranceOrderReconciler(Decimal("0.001"), Decimal("0.001"))
result = actual.reconcile(model_state, existing, desired)
assert result.to_place == desired
assert result.to_cancel == existing
assert result.to_keep == []
assert result.to_ignore == []
def test_reconcile_all_acceptable_orders() -> None:
existing = [
mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(99), quantity=Decimal(10)),
mango.Order.from_basic_info(mango.Side.SELL, price=Decimal(101), quantity=Decimal(10))
]
desired = [
mango.Order.from_basic_info(mango.Side.BUY, price=Decimal("99.01"), quantity=Decimal(10)),
mango.Order.from_basic_info(mango.Side.SELL, price=Decimal("101.01"), quantity=Decimal(10))
]
model_state = fake_model_state()
actual = ToleranceOrderReconciler(Decimal("0.001"), Decimal("0.001"))
result = actual.reconcile(model_state, existing, desired)
assert result.to_place == []
assert result.to_cancel == []
assert result.to_keep == existing
assert result.to_ignore == desired
def test_reconcile_different_list_sizes_orders() -> None:
existing = [
mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(98), quantity=Decimal(20)),
mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(99), quantity=Decimal(10)),
mango.Order.from_basic_info(mango.Side.SELL, price=Decimal(101), quantity=Decimal(10)),
mango.Order.from_basic_info(mango.Side.SELL, price=Decimal(102), quantity=Decimal(20))
]
desired = [
mango.Order.from_basic_info(mango.Side.BUY, price=Decimal("99.01"), quantity=Decimal(10)),
mango.Order.from_basic_info(mango.Side.SELL, price=Decimal("101.01"), quantity=Decimal(10))
]
model_state = fake_model_state()
actual = ToleranceOrderReconciler(Decimal("0.001"), Decimal("0.001"))
result = actual.reconcile(model_state, existing, desired)
assert result.to_place == []
assert len(result.to_cancel) == 2
assert result.to_cancel[0] == existing[0]
assert result.to_cancel[1] == existing[3]
assert len(result.to_keep) == 2
assert result.to_keep[0] == existing[1]
assert result.to_keep[1] == existing[2]
assert result.to_ignore == desired
def test_reconcile_two_acceptable_two_unacceptable_orders() -> None:
existing = [
mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(98), quantity=Decimal(20)),
mango.Order.from_basic_info(mango.Side.BUY, price=Decimal(99), quantity=Decimal(10)),
mango.Order.from_basic_info(mango.Side.SELL, price=Decimal(101), quantity=Decimal(10)),
mango.Order.from_basic_info(mango.Side.SELL, price=Decimal(102), quantity=Decimal(20))
]
desired = [
mango.Order.from_basic_info(mango.Side.BUY, price=Decimal("98.1"), quantity=Decimal(20)),
mango.Order.from_basic_info(mango.Side.BUY, price=Decimal("99.01"), quantity=Decimal(10)),
mango.Order.from_basic_info(mango.Side.SELL, price=Decimal("101.01"), quantity=Decimal(10)),
mango.Order.from_basic_info(mango.Side.SELL, price=Decimal("102.11"), quantity=Decimal(20))
]
model_state = fake_model_state()
actual = ToleranceOrderReconciler(Decimal("0.001"), Decimal("0.001"))
result = actual.reconcile(model_state, existing, desired)
assert len(result.to_place) == 2
assert len(result.to_cancel) == 2
assert len(result.to_keep) == 2
assert len(result.to_ignore) == 2
# Desired 1 outcomes
assert result.to_place[0] == desired[0]
assert result.to_cancel[0] == existing[0]
# Desired 2 outcomes
assert result.to_keep[0] == existing[1]
assert result.to_ignore[0] == desired[1]
# Desired 3 outcomes
assert result.to_keep[1] == existing[2]
assert result.to_ignore[1] == desired[2]
# Desired 4 outcomes
assert result.to_place[1] == desired[3]
assert result.to_cancel[1] == existing[3]