|
|
|
|
|
|
|
|
|
module TestLOB
|
|
|
|
|
(
|
|
|
|
|
tests
|
|
|
|
|
) where
|
|
|
|
|
|
|
|
|
|
import ATrade.ESim.Core
|
|
|
|
|
(MatchingAction (..), PriceTick (PriceTick), Volume (..), addToLob, emptyLob, executeMatchingActions)
|
|
|
|
|
import ATrade.Types (Operation (..), Order (..), OrderPrice (..), OrderState (..), Price, SignalId (..))
|
|
|
|
|
import Hedgehog
|
|
|
|
|
import Hedgehog.Gen qualified as Gen
|
|
|
|
|
import Hedgehog.Range qualified as Range
|
|
|
|
|
import Test.Tasty
|
|
|
|
|
import Test.Tasty.Hedgehog
|
|
|
|
|
|
|
|
|
|
tests :: TestTree
|
|
|
|
|
tests = testGroup "LimitOrderBook"
|
|
|
|
|
[
|
|
|
|
|
testProperty "add to empty LOB => enqueues order" prop_add_to_empty_lob,
|
|
|
|
|
testProperty "full match" prop_full_match
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
prop_add_to_empty_lob :: Property
|
|
|
|
|
prop_add_to_empty_lob = property $ do
|
|
|
|
|
priceTick <- forAll $ Gen.integral (Range.linear 1 100000)
|
|
|
|
|
order <- forAll $
|
|
|
|
|
Order <$> Gen.integral (Range.linear 1 100000)
|
|
|
|
|
<*> Gen.text (Range.linear 1 50) Gen.unicode
|
|
|
|
|
<*> Gen.text (Range.linear 1 50) Gen.unicode
|
|
|
|
|
<*> pure (Limit $ fromInteger priceTick * tickSize)
|
|
|
|
|
<*> Gen.integral (Range.linear 1 10000)
|
|
|
|
|
<*> pure 0
|
|
|
|
|
<*> pure Buy
|
|
|
|
|
<*> pure Unsubmitted
|
|
|
|
|
<*> pure (SignalId "test" "foo" "")
|
|
|
|
|
addToLob order lob === [Enqueue (orderId order) (PriceTick . fromInteger $ priceTick) (Volume . fromIntegral $ orderQuantity order) (orderOperation order)]
|
|
|
|
|
where
|
|
|
|
|
lob = emptyLob "Test" tickSize
|
|
|
|
|
tickSize :: Price
|
|
|
|
|
tickSize = 0.1
|
|
|
|
|
|
|
|
|
|
prop_full_match :: Property
|
|
|
|
|
prop_full_match = property $ do
|
|
|
|
|
priceTick <- forAll $ Gen.integral (Range.linear 1 100000)
|
|
|
|
|
order <- forAll $
|
|
|
|
|
Order <$> Gen.integral (Range.linear 1 100000)
|
|
|
|
|
<*> Gen.text (Range.linear 1 50) Gen.unicode
|
|
|
|
|
<*> Gen.text (Range.linear 1 50) Gen.unicode
|
|
|
|
|
<*> pure Market
|
|
|
|
|
<*> Gen.integral (Range.linear 1 10000)
|
|
|
|
|
<*> pure 0
|
|
|
|
|
<*> pure Buy
|
|
|
|
|
<*> pure Unsubmitted
|
|
|
|
|
<*> pure (SignalId "test" "foo" "")
|
|
|
|
|
addToLob order (lob order priceTick) === [Match (orderId order) 1 (orderOperation order) (PriceTick priceTick) (Volume . fromIntegral $ orderQuantity order)]
|
|
|
|
|
where
|
|
|
|
|
lob order priceTick = executeMatchingActions lob0 [Enqueue 1 (PriceTick priceTick) (Volume . fromIntegral $ orderQuantity order) Sell]
|
|
|
|
|
lob0 = emptyLob "Test" tickSize
|
|
|
|
|
tickSize = 0.1
|
|
|
|
|
|