Added PerpEventQueue.events_for_account() and PerpEventQueue.fills_for_account(), UnseenAccountFillEventTracker and tests.
This commit is contained in:
parent
0e8e815c81
commit
e372fb932c
|
@ -177,6 +177,7 @@ from .perpeventqueue import PerpEventQueue as PerpEventQueue
|
|||
from .perpeventqueue import PerpFillEvent as PerpFillEvent
|
||||
from .perpeventqueue import PerpOutEvent as PerpOutEvent
|
||||
from .perpeventqueue import PerpUnknownEvent as PerpUnknownEvent
|
||||
from .perpeventqueue import UnseenAccountFillEventTracker as UnseenAccountFillEventTracker
|
||||
from .perpeventqueue import UnseenPerpEventChangesTracker as UnseenPerpEventChangesTracker
|
||||
from .perpmarket import PerpMarket as PerpMarket
|
||||
from .perpmarket import PerpMarketStub as PerpMarketStub
|
||||
|
|
|
@ -76,6 +76,10 @@ class PerpFillEvent(PerpEvent):
|
|||
self.taker_order_id: Decimal = taker_order_id
|
||||
self.taker_client_order_id: Decimal = taker_client_order_id
|
||||
|
||||
@property
|
||||
def key(self) -> str:
|
||||
return f"{self.maker_order_id}/{self.taker_order_id}"
|
||||
|
||||
@property
|
||||
def accounts_to_crank(self) -> typing.Sequence[PublicKey]:
|
||||
return [self.maker, self.taker]
|
||||
|
@ -253,6 +257,20 @@ class PerpEventQueue(AddressableAccount):
|
|||
|
||||
return distinct
|
||||
|
||||
def events_for_account(self, mango_account_address: PublicKey) -> typing.Sequence[PerpEvent]:
|
||||
events: typing.List[PerpEvent] = []
|
||||
for event in [*self.processed_events, *self.unprocessed_events]:
|
||||
if mango_account_address in event.accounts_to_crank:
|
||||
events += [event]
|
||||
return events
|
||||
|
||||
def fills_for_account(self, mango_account_address: PublicKey) -> typing.Sequence[PerpFillEvent]:
|
||||
fills: typing.List[PerpFillEvent] = []
|
||||
for event in self.events_for_account(mango_account_address):
|
||||
if isinstance(event, PerpFillEvent):
|
||||
fills += [event]
|
||||
return fills
|
||||
|
||||
@ property
|
||||
def capacity(self) -> int:
|
||||
return len(self.unprocessed_events) + len(self.processed_events)
|
||||
|
@ -298,3 +316,40 @@ class UnseenPerpEventChangesTracker:
|
|||
self.last_sequence_number = new_sequence_number
|
||||
|
||||
return unseen
|
||||
|
||||
|
||||
# # 🥭 UnseenAccountFillEventTracker class
|
||||
#
|
||||
# `UnseenAccountFillEventTracker` tracks fills for a specific Mango Account in a specific
|
||||
# `PerpEventQueue`. When an updated version of the `PerpEventQueue` is passed to `unseen()`,
|
||||
# any new fills are returned.
|
||||
#
|
||||
class UnseenAccountFillEventTracker:
|
||||
def __init__(self, initial: PerpEventQueue, mango_account_address: PublicKey) -> None:
|
||||
self.mango_account_address: PublicKey = mango_account_address
|
||||
self.last_sequence_number: Decimal = initial.sequence_number
|
||||
initial_fills: typing.Sequence[PerpFillEvent] = initial.fills_for_account(mango_account_address)
|
||||
self.last_key: str = initial_fills[-1].key if len(initial_fills) > 0 else ""
|
||||
|
||||
def unseen(self, event_queue: PerpEventQueue) -> typing.Sequence[PerpEvent]:
|
||||
fills: typing.Sequence[PerpFillEvent] = event_queue.fills_for_account(self.mango_account_address)
|
||||
if len(fills) == 0:
|
||||
return []
|
||||
|
||||
last_key_position: int = -1
|
||||
for counter, fill in enumerate(fills):
|
||||
if fill.key == self.last_key:
|
||||
last_key_position = counter
|
||||
break
|
||||
|
||||
unseen: typing.Sequence[PerpFillEvent]
|
||||
if last_key_position == -1:
|
||||
# We haven't seen any of these fills
|
||||
unseen = fills
|
||||
elif last_key_position == len(fills) - 1:
|
||||
unseen = []
|
||||
else:
|
||||
unseen = fills[last_key_position + 1:]
|
||||
self.last_key = unseen[-1].key
|
||||
|
||||
return unseen
|
||||
|
|
|
@ -5,6 +5,7 @@ from solana.publickey import PublicKey
|
|||
from .context import mango
|
||||
from .fakes import fake_account_info, fake_seeded_public_key
|
||||
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
|
||||
|
||||
|
@ -50,6 +51,17 @@ class TstPE(mango.PerpEvent):
|
|||
return f"« TstPE [{self.event_type}] »"
|
||||
|
||||
|
||||
class TstFillPE(mango.PerpFillEvent):
|
||||
def __init__(self, maker: PublicKey, maker_id: int, taker: PublicKey, taker_id: int):
|
||||
super().__init__(0, Decimal(0), datetime.now(), mango.Side.BUY,
|
||||
Decimal(1), Decimal(1), Decimal(1), Decimal(1), True,
|
||||
maker, Decimal(maker_id), Decimal(0),
|
||||
taker, Decimal(taker_id), Decimal(0))
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"« TstFillPE [{self.maker_order_id} / {self.taker_order_id}] »"
|
||||
|
||||
|
||||
def test_unseen_with_no_changes() -> None:
|
||||
initial = _fake_pev(Decimal(5), Decimal(2), Decimal(7), [], [TstPE(), TstPE(), TstPE(), TstPE(), TstPE()])
|
||||
actual: mango.UnseenPerpEventChangesTracker = mango.UnseenPerpEventChangesTracker(initial)
|
||||
|
@ -123,3 +135,97 @@ def test_unseen_with_two_unprocessed_changes_wrapping_around() -> None:
|
|||
assert len(unseen) == 2
|
||||
assert unseen[0] == marker1
|
||||
assert unseen[1] == marker2
|
||||
|
||||
|
||||
def test_fills_for_account() -> None:
|
||||
user1 = fake_seeded_public_key("user1")
|
||||
user2 = fake_seeded_public_key("user2")
|
||||
user3 = fake_seeded_public_key("user3")
|
||||
order1 = TstFillPE(user1, 11, user2, 21)
|
||||
order2 = TstFillPE(user2, 12, user3, 22)
|
||||
order3 = TstFillPE(user3, 13, user1, 23)
|
||||
pev = _fake_pev(Decimal(4), Decimal(0), Decimal(7), [], [order1, order2, order3])
|
||||
|
||||
my_fills = pev.fills_for_account(user1)
|
||||
assert len(my_fills) == 2
|
||||
assert my_fills[0] == order1
|
||||
assert my_fills[1] == order3
|
||||
|
||||
|
||||
def test_no_fills_for_account() -> None:
|
||||
user1 = fake_seeded_public_key("user1")
|
||||
user2 = fake_seeded_public_key("user2")
|
||||
user3 = fake_seeded_public_key("user3")
|
||||
user4 = fake_seeded_public_key("user4")
|
||||
order1 = TstFillPE(user1, 11, user2, 21)
|
||||
order2 = TstFillPE(user2, 12, user3, 22)
|
||||
order3 = TstFillPE(user3, 13, user1, 23)
|
||||
pev = _fake_pev(Decimal(4), Decimal(0), Decimal(7), [], [order1, order2, order3])
|
||||
|
||||
my_fills = pev.fills_for_account(user4)
|
||||
assert len(my_fills) == 0
|
||||
|
||||
|
||||
def test_unseen_fills_for_account() -> None:
|
||||
user1 = fake_seeded_public_key("user1")
|
||||
user2 = fake_seeded_public_key("user2")
|
||||
user3 = fake_seeded_public_key("user3")
|
||||
order1 = TstFillPE(user1, 11, user2, 21)
|
||||
order2 = TstFillPE(user2, 12, user3, 22)
|
||||
order3 = TstFillPE(user3, 13, user1, 23)
|
||||
pev1 = _fake_pev(Decimal(4), Decimal(0), Decimal(7), [], [order1, order2, order3])
|
||||
|
||||
actual = mango.UnseenAccountFillEventTracker(pev1, user1)
|
||||
|
||||
order4 = TstFillPE(user3, 14, user2, 24)
|
||||
order5 = TstFillPE(user1, 15, user3, 25)
|
||||
order6 = TstFillPE(user2, 16, user1, 26)
|
||||
pev2 = _fake_pev(Decimal(4), Decimal(0), Decimal(7), [], [order1, order2, order3, order4, order5, order6])
|
||||
|
||||
my_unseen_fills = actual.unseen(pev2)
|
||||
assert len(my_unseen_fills) == 2
|
||||
assert my_unseen_fills[0] == order5
|
||||
assert my_unseen_fills[1] == order6
|
||||
|
||||
|
||||
def test_no_unseen_fills_for_account() -> None:
|
||||
# Exactly the same test as before but with user4 as the account we're watching for.
|
||||
user1 = fake_seeded_public_key("user1")
|
||||
user2 = fake_seeded_public_key("user2")
|
||||
user3 = fake_seeded_public_key("user3")
|
||||
user4 = fake_seeded_public_key("user4")
|
||||
order1 = TstFillPE(user1, 11, user2, 21)
|
||||
order2 = TstFillPE(user2, 12, user3, 22)
|
||||
order3 = TstFillPE(user3, 13, user1, 23)
|
||||
pev1 = _fake_pev(Decimal(4), Decimal(0), Decimal(7), [], [order1, order2, order3])
|
||||
|
||||
actual = mango.UnseenAccountFillEventTracker(pev1, user4)
|
||||
|
||||
order4 = TstFillPE(user3, 14, user2, 24)
|
||||
order5 = TstFillPE(user1, 15, user3, 25)
|
||||
order6 = TstFillPE(user2, 16, user1, 26)
|
||||
pev2 = _fake_pev(Decimal(4), Decimal(0), Decimal(7), [], [order1, order2, order3, order4, order5, order6])
|
||||
|
||||
my_unseen_fills = actual.unseen(pev2)
|
||||
assert len(my_unseen_fills) == 0
|
||||
|
||||
|
||||
def test_no_changes_in_unseen_fills_for_account() -> None:
|
||||
user1 = fake_seeded_public_key("user1")
|
||||
user2 = fake_seeded_public_key("user2")
|
||||
user3 = fake_seeded_public_key("user3")
|
||||
user4 = fake_seeded_public_key("user4")
|
||||
order1 = TstFillPE(user1, 11, user2, 21)
|
||||
order2 = TstFillPE(user2, 12, user3, 22)
|
||||
order3 = TstFillPE(user3, 13, user1, 23)
|
||||
pev1 = _fake_pev(Decimal(4), Decimal(0), Decimal(7), [], [order1, order2, order3])
|
||||
|
||||
actual = mango.UnseenAccountFillEventTracker(pev1, user1)
|
||||
|
||||
order4 = TstFillPE(user3, 14, user2, 24)
|
||||
order5 = TstFillPE(user4, 15, user3, 25)
|
||||
order6 = TstFillPE(user2, 16, user4, 26)
|
||||
pev2 = _fake_pev(Decimal(4), Decimal(0), Decimal(7), [], [order1, order2, order3, order4, order5, order6])
|
||||
|
||||
my_unseen_fills = actual.unseen(pev2)
|
||||
assert len(my_unseen_fills) == 0
|
||||
|
|
Loading…
Reference in New Issue