2021-06-25 02:33:40 -07:00
|
|
|
|
# # ⚠ Warning
|
|
|
|
|
#
|
|
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
|
|
|
# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
|
|
|
# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
|
|
|
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
|
|
|
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
#
|
|
|
|
|
# [🥭 Mango Markets](https://mango.markets/) support is available at:
|
|
|
|
|
# [Docs](https://docs.mango.markets/)
|
|
|
|
|
# [Discord](https://discord.gg/67jySBhxrg)
|
|
|
|
|
# [Twitter](https://twitter.com/mangomarkets)
|
|
|
|
|
# [Github](https://github.com/blockworks-foundation)
|
|
|
|
|
# [Email](mailto:hello@blockworks.foundation)
|
|
|
|
|
|
2021-07-23 06:18:26 -07:00
|
|
|
|
import typing
|
|
|
|
|
|
2021-06-25 02:33:40 -07:00
|
|
|
|
from solana.publickey import PublicKey
|
|
|
|
|
|
|
|
|
|
from .accountinfo import AccountInfo
|
|
|
|
|
from .context import Context
|
2021-06-25 07:50:37 -07:00
|
|
|
|
from .group import Group
|
2021-07-28 09:43:58 -07:00
|
|
|
|
from .lotsizeconverter import LotSizeConverter
|
2021-07-23 06:18:26 -07:00
|
|
|
|
from .market import Market, InventorySource
|
|
|
|
|
from .orderbookside import OrderBookSide
|
|
|
|
|
from .orders import Order
|
|
|
|
|
from .perpeventqueue import PerpEvent, PerpEventQueue
|
|
|
|
|
from .perpmarketdetails import PerpMarketDetails
|
|
|
|
|
from .token import Token
|
|
|
|
|
|
2021-06-25 02:33:40 -07:00
|
|
|
|
|
|
|
|
|
# # 🥭 PerpMarket class
|
|
|
|
|
#
|
2021-07-23 06:18:26 -07:00
|
|
|
|
# This class encapsulates our knowledge of a Mango perps market.
|
|
|
|
|
#
|
|
|
|
|
class PerpMarket(Market):
|
2021-08-19 03:00:39 -07:00
|
|
|
|
def __init__(self, program_id: PublicKey, address: PublicKey, base: Token, quote: Token, underlying_perp_market: PerpMarketDetails):
|
|
|
|
|
super().__init__(program_id, address, InventorySource.ACCOUNT, base, quote)
|
2021-07-23 06:18:26 -07:00
|
|
|
|
self.underlying_perp_market: PerpMarketDetails = underlying_perp_market
|
2021-07-28 09:43:58 -07:00
|
|
|
|
self.lot_size_converter: LotSizeConverter = LotSizeConverter(
|
|
|
|
|
base, underlying_perp_market.base_lot_size, quote, underlying_perp_market.quote_lot_size)
|
2021-07-23 06:18:26 -07:00
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def symbol(self) -> str:
|
|
|
|
|
return f"{self.base.symbol}-PERP"
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def group(self) -> Group:
|
|
|
|
|
return self.underlying_perp_market.group
|
|
|
|
|
|
|
|
|
|
def unprocessed_events(self, context: Context) -> typing.Sequence[PerpEvent]:
|
2021-07-28 09:43:58 -07:00
|
|
|
|
event_queue: PerpEventQueue = PerpEventQueue.load(
|
|
|
|
|
context, self.underlying_perp_market.event_queue, self.lot_size_converter)
|
2021-08-01 09:47:45 -07:00
|
|
|
|
return event_queue.unprocessed_events
|
2021-07-23 06:18:26 -07:00
|
|
|
|
|
|
|
|
|
def accounts_to_crank(self, context: Context, additional_account_to_crank: typing.Optional[PublicKey]) -> typing.Sequence[PublicKey]:
|
|
|
|
|
accounts_to_crank: typing.List[PublicKey] = []
|
|
|
|
|
for event_to_crank in self.unprocessed_events(context):
|
|
|
|
|
accounts_to_crank += event_to_crank.accounts_to_crank
|
|
|
|
|
|
|
|
|
|
if additional_account_to_crank is not None:
|
|
|
|
|
accounts_to_crank += [additional_account_to_crank]
|
|
|
|
|
|
|
|
|
|
seen = []
|
|
|
|
|
distinct = []
|
|
|
|
|
for account in accounts_to_crank:
|
|
|
|
|
account_str = account.to_base58()
|
|
|
|
|
if account_str not in seen:
|
|
|
|
|
distinct += [account]
|
|
|
|
|
seen += [account_str]
|
|
|
|
|
distinct.sort(key=lambda address: address._key or [0])
|
|
|
|
|
return distinct
|
|
|
|
|
|
|
|
|
|
def orders(self, context: Context) -> typing.Sequence[Order]:
|
|
|
|
|
bids_address: PublicKey = self.underlying_perp_market.bids
|
|
|
|
|
asks_address: PublicKey = self.underlying_perp_market.asks
|
|
|
|
|
[bids, asks] = AccountInfo.load_multiple(context, [bids_address, asks_address])
|
|
|
|
|
bid_side = OrderBookSide.parse(context, bids, self.underlying_perp_market)
|
|
|
|
|
ask_side = OrderBookSide.parse(context, asks, self.underlying_perp_market)
|
|
|
|
|
return [*bid_side.orders(), *ask_side.orders()]
|
|
|
|
|
|
|
|
|
|
def __str__(self) -> str:
|
2021-07-28 09:43:58 -07:00
|
|
|
|
underlying: str = f"{self.underlying_perp_market}".replace("\n", "\n ")
|
2021-08-19 03:00:39 -07:00
|
|
|
|
return f"""« 𝙿𝚎𝚛𝚙𝙼𝚊𝚛𝚔𝚎𝚝 {self.symbol} {self.address} [{self.program_id}]
|
2021-07-28 09:43:58 -07:00
|
|
|
|
{underlying}
|
|
|
|
|
»"""
|
2021-07-23 06:18:26 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# # 🥭 PerpMarketStub class
|
2021-06-25 02:33:40 -07:00
|
|
|
|
#
|
2021-07-23 06:18:26 -07:00
|
|
|
|
# This class holds information to load a `PerpMarket` object but doesn't automatically load it.
|
|
|
|
|
#
|
|
|
|
|
class PerpMarketStub(Market):
|
2021-08-19 03:00:39 -07:00
|
|
|
|
def __init__(self, program_id: PublicKey, address: PublicKey, base: Token, quote: Token, group_address: PublicKey):
|
|
|
|
|
super().__init__(program_id, address, InventorySource.ACCOUNT, base, quote)
|
2021-07-23 06:18:26 -07:00
|
|
|
|
self.group_address: PublicKey = group_address
|
|
|
|
|
|
|
|
|
|
def load(self, context: Context, group: typing.Optional[Group] = None) -> PerpMarket:
|
|
|
|
|
actual_group: Group = group or Group.load(context, self.group_address)
|
|
|
|
|
underlying_perp_market: PerpMarketDetails = PerpMarketDetails.load(context, self.address, actual_group)
|
2021-08-19 03:00:39 -07:00
|
|
|
|
return PerpMarket(self.program_id, self.address, self.base, self.quote, underlying_perp_market)
|
2021-06-25 02:33:40 -07:00
|
|
|
|
|
2021-07-23 06:18:26 -07:00
|
|
|
|
@property
|
|
|
|
|
def symbol(self) -> str:
|
|
|
|
|
return f"{self.base.symbol}-PERP"
|
2021-06-25 02:33:40 -07:00
|
|
|
|
|
2021-07-23 06:18:26 -07:00
|
|
|
|
def __str__(self) -> str:
|
2021-08-19 03:00:39 -07:00
|
|
|
|
return f"« 𝙿𝚎𝚛𝚙𝙼𝚊𝚛𝚔𝚎𝚝𝚂𝚝𝚞𝚋 {self.symbol} {self.address} [{self.program_id}] »"
|