2021-08-24 12:13:44 -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)
|
|
|
|
|
|
|
|
|
|
import abc
|
|
|
|
|
import logging
|
|
|
|
|
import mango
|
|
|
|
|
import time
|
|
|
|
|
import typing
|
|
|
|
|
|
2021-08-27 12:37:23 -07:00
|
|
|
|
from decimal import Decimal
|
2021-08-24 12:13:44 -07:00
|
|
|
|
from solana.publickey import PublicKey
|
|
|
|
|
|
2021-10-02 04:28:16 -07:00
|
|
|
|
from ..modelstate import ModelState
|
2021-08-27 12:37:23 -07:00
|
|
|
|
from ..tokenvalue import TokenValue
|
2021-08-24 12:13:44 -07:00
|
|
|
|
|
2021-10-04 10:27:07 -07:00
|
|
|
|
from ..calculators.collateralcalculator import CollateralCalculator
|
|
|
|
|
from ..calculators.perpcollateralcalculator import PerpCollateralCalculator
|
|
|
|
|
from ..calculators.spotcollateralcalculator import SpotCollateralCalculator
|
2021-08-24 12:13:44 -07:00
|
|
|
|
|
|
|
|
|
# # 🥭 ModelStateBuilder class
|
|
|
|
|
#
|
|
|
|
|
# Base class for building a `ModelState` through polling or websockets.
|
|
|
|
|
#
|
2021-10-04 10:27:07 -07:00
|
|
|
|
|
|
|
|
|
|
2021-08-24 12:13:44 -07:00
|
|
|
|
class ModelStateBuilder(metaclass=abc.ABCMeta):
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.logger: logging.Logger = logging.getLogger(self.__class__.__name__)
|
|
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
|
def build(self, context: mango.Context) -> ModelState:
|
|
|
|
|
raise NotImplementedError("ModelStateBuilder.build() is not implemented on the base type.")
|
|
|
|
|
|
|
|
|
|
def __str__(self) -> str:
|
|
|
|
|
return "« 𝙼𝚘𝚍𝚎𝚕𝚂𝚝𝚊𝚝𝚎𝙱𝚞𝚒𝚕𝚍𝚎𝚛 »"
|
|
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
|
return f"{self}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# # 🥭 WebsocketModelStateBuilder class
|
|
|
|
|
#
|
|
|
|
|
# Base class for building a `ModelState` through polling.
|
|
|
|
|
#
|
|
|
|
|
class WebsocketModelStateBuilder(ModelStateBuilder):
|
|
|
|
|
def __init__(self, model_state: ModelState):
|
|
|
|
|
super().__init__()
|
|
|
|
|
self.model_state: ModelState = model_state
|
|
|
|
|
|
|
|
|
|
def build(self, context: mango.Context) -> ModelState:
|
|
|
|
|
return self.model_state
|
|
|
|
|
|
|
|
|
|
def __str__(self) -> str:
|
|
|
|
|
return f"« 𝚆𝚎𝚋𝚜𝚘𝚌𝚔𝚎𝚝𝙼𝚘𝚍𝚎𝚕𝚂𝚝𝚊𝚝𝚎𝙱𝚞𝚒𝚕𝚍𝚎𝚛 for market '{self.model_state.market.symbol}' »"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# # 🥭 PollingModelStateBuilder class
|
|
|
|
|
#
|
|
|
|
|
# Base class for building a `ModelState` through polling.
|
|
|
|
|
#
|
|
|
|
|
class PollingModelStateBuilder(ModelStateBuilder):
|
|
|
|
|
def __init__(self):
|
|
|
|
|
super().__init__()
|
|
|
|
|
|
|
|
|
|
def build(self, context: mango.Context) -> ModelState:
|
|
|
|
|
started_at = time.time()
|
|
|
|
|
built: ModelState = self.poll(context)
|
|
|
|
|
time_taken = time.time() - started_at
|
|
|
|
|
self.logger.debug(f"Poll for model state complete. Time taken: {time_taken:.2f} seconds.")
|
|
|
|
|
return built
|
|
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
|
def poll(self, context: mango.Context) -> ModelState:
|
|
|
|
|
raise NotImplementedError("PollingModelStateBuilder.poll() is not implemented on the base type.")
|
|
|
|
|
|
2021-09-02 05:11:35 -07:00
|
|
|
|
def from_values(self, order_owner: PublicKey, market: mango.Market, group: mango.Group, account: mango.Account,
|
|
|
|
|
price: mango.Price, placed_orders_container: mango.PlacedOrdersContainer,
|
|
|
|
|
inventory: mango.Inventory, bids: typing.Sequence[mango.Order],
|
|
|
|
|
asks: typing.Sequence[mango.Order]) -> ModelState:
|
2021-08-24 12:13:44 -07:00
|
|
|
|
group_watcher: mango.ManualUpdateWatcher[mango.Group] = mango.ManualUpdateWatcher(group)
|
|
|
|
|
account_watcher: mango.ManualUpdateWatcher[mango.Account] = mango.ManualUpdateWatcher(account)
|
|
|
|
|
price_watcher: mango.ManualUpdateWatcher[mango.Price] = mango.ManualUpdateWatcher(price)
|
|
|
|
|
placed_orders_container_watcher: mango.ManualUpdateWatcher[
|
|
|
|
|
mango.PlacedOrdersContainer] = mango.ManualUpdateWatcher(placed_orders_container)
|
|
|
|
|
inventory_watcher: mango.ManualUpdateWatcher[mango.Inventory] = mango.ManualUpdateWatcher(inventory)
|
|
|
|
|
bids_watcher: mango.ManualUpdateWatcher[typing.Sequence[mango.Order]] = mango.ManualUpdateWatcher(bids)
|
|
|
|
|
asks_watcher: mango.ManualUpdateWatcher[typing.Sequence[mango.Order]] = mango.ManualUpdateWatcher(asks)
|
|
|
|
|
|
2021-09-02 05:11:35 -07:00
|
|
|
|
return ModelState(order_owner, market, group_watcher, account_watcher, price_watcher,
|
2021-08-24 12:13:44 -07:00
|
|
|
|
placed_orders_container_watcher, inventory_watcher, bids_watcher, asks_watcher)
|
|
|
|
|
|
|
|
|
|
def __str__(self) -> str:
|
|
|
|
|
return "« 𝙿𝚘𝚕𝚕𝚒𝚗𝚐𝙼𝚘𝚍𝚎𝚕𝚂𝚝𝚊𝚝𝚎𝙱𝚞𝚒𝚕𝚍𝚎𝚛 »"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# # 🥭 SerumPollingModelStateBuilder class
|
|
|
|
|
#
|
|
|
|
|
# Polls Solana and builds a `ModelState` for a `SerumMarket`
|
|
|
|
|
#
|
|
|
|
|
class SerumPollingModelStateBuilder(PollingModelStateBuilder):
|
|
|
|
|
def __init__(self,
|
2021-09-02 05:11:35 -07:00
|
|
|
|
order_owner: PublicKey,
|
2021-08-24 12:13:44 -07:00
|
|
|
|
market: mango.SerumMarket,
|
|
|
|
|
oracle: mango.Oracle,
|
|
|
|
|
group_address: PublicKey,
|
|
|
|
|
account_address: PublicKey,
|
|
|
|
|
open_orders_address: PublicKey,
|
|
|
|
|
base_inventory_token_account: mango.TokenAccount,
|
|
|
|
|
quote_inventory_token_account: mango.TokenAccount,
|
|
|
|
|
):
|
|
|
|
|
super().__init__()
|
2021-09-02 05:11:35 -07:00
|
|
|
|
self.order_owner: PublicKey = order_owner
|
2021-08-24 12:13:44 -07:00
|
|
|
|
self.market: mango.SerumMarket = market
|
|
|
|
|
self.oracle: mango.Oracle = oracle
|
|
|
|
|
|
|
|
|
|
self.group_address: PublicKey = group_address
|
|
|
|
|
self.account_address: PublicKey = account_address
|
|
|
|
|
self.open_orders_address: PublicKey = open_orders_address
|
|
|
|
|
self.base_inventory_token_account: mango.TokenAccount = base_inventory_token_account
|
|
|
|
|
self.quote_inventory_token_account: mango.TokenAccount = quote_inventory_token_account
|
|
|
|
|
|
|
|
|
|
def poll(self, context: mango.Context) -> ModelState:
|
|
|
|
|
addresses: typing.List[PublicKey] = [
|
|
|
|
|
self.group_address,
|
|
|
|
|
self.account_address,
|
|
|
|
|
self.open_orders_address,
|
|
|
|
|
self.base_inventory_token_account.address,
|
|
|
|
|
self.quote_inventory_token_account.address,
|
|
|
|
|
self.market.underlying_serum_market.state.bids(),
|
|
|
|
|
self.market.underlying_serum_market.state.asks()
|
|
|
|
|
]
|
|
|
|
|
account_infos: typing.Sequence[mango.AccountInfo] = mango.AccountInfo.load_multiple(context, addresses)
|
|
|
|
|
group: mango.Group = mango.Group.parse(context, account_infos[0])
|
|
|
|
|
account: mango.Account = mango.Account.parse(account_infos[1], group)
|
|
|
|
|
placed_orders_container: mango.PlacedOrdersContainer = mango.OpenOrders.parse(
|
|
|
|
|
account_infos[2], self.market.base.decimals, self.market.quote.decimals)
|
|
|
|
|
|
2021-08-27 12:37:23 -07:00
|
|
|
|
# Serum markets don't accrue MNGO liquidity incentives
|
|
|
|
|
mngo = group.find_token_info_by_symbol("MNGO").token
|
|
|
|
|
mngo_accrued: TokenValue = TokenValue(mngo, Decimal(0))
|
|
|
|
|
|
2021-08-24 12:13:44 -07:00
|
|
|
|
base_inventory_token_account = mango.TokenAccount.parse(
|
|
|
|
|
account_infos[3], self.base_inventory_token_account.value.token)
|
|
|
|
|
quote_inventory_token_account = mango.TokenAccount.parse(
|
|
|
|
|
account_infos[4], self.quote_inventory_token_account.value.token)
|
|
|
|
|
|
2021-09-30 10:53:33 -07:00
|
|
|
|
# Both these will have top-of-book at index 0.
|
2021-08-24 12:13:44 -07:00
|
|
|
|
bids: typing.Sequence[mango.Order] = mango.parse_account_info_to_orders(
|
|
|
|
|
account_infos[5], self.market.underlying_serum_market)
|
|
|
|
|
asks: typing.Sequence[mango.Order] = mango.parse_account_info_to_orders(
|
|
|
|
|
account_infos[6], self.market.underlying_serum_market)
|
|
|
|
|
|
|
|
|
|
price: mango.Price = self.oracle.fetch_price(context)
|
|
|
|
|
|
2021-08-30 16:30:22 -07:00
|
|
|
|
available: Decimal = (base_inventory_token_account.value.value * price.mid_price) + \
|
|
|
|
|
quote_inventory_token_account.value.value
|
|
|
|
|
available_collateral: TokenValue = TokenValue(quote_inventory_token_account.value.token, available)
|
|
|
|
|
inventory: mango.Inventory = mango.Inventory(mango.InventorySource.SPL_TOKENS,
|
|
|
|
|
mngo_accrued,
|
|
|
|
|
available_collateral,
|
|
|
|
|
base_inventory_token_account.value,
|
|
|
|
|
quote_inventory_token_account.value)
|
|
|
|
|
|
2021-09-02 05:11:35 -07:00
|
|
|
|
return self.from_values(self.order_owner, self.market, group, account, price, placed_orders_container, inventory, bids, asks)
|
2021-08-24 12:13:44 -07:00
|
|
|
|
|
|
|
|
|
def __str__(self) -> str:
|
|
|
|
|
return f"""« 𝚂𝚎𝚛𝚞𝚖𝙿𝚘𝚕𝚕𝚒𝚗𝚐𝙼𝚘𝚍𝚎𝚕𝚂𝚝𝚊𝚝𝚎𝙱𝚞𝚒𝚕𝚍𝚎𝚛 for market '{self.market.symbol}' »"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# # 🥭 SpotPollingModelStateBuilder class
|
|
|
|
|
#
|
|
|
|
|
# Polls Solana and builds a `ModelState` for a `SpotMarket`
|
|
|
|
|
#
|
|
|
|
|
class SpotPollingModelStateBuilder(PollingModelStateBuilder):
|
|
|
|
|
def __init__(self,
|
2021-09-02 05:11:35 -07:00
|
|
|
|
order_owner: PublicKey,
|
2021-08-24 12:13:44 -07:00
|
|
|
|
market: mango.SpotMarket,
|
|
|
|
|
oracle: mango.Oracle,
|
|
|
|
|
group_address: PublicKey,
|
2021-08-30 16:30:22 -07:00
|
|
|
|
cache_address: PublicKey,
|
2021-08-24 12:13:44 -07:00
|
|
|
|
account_address: PublicKey,
|
2021-09-09 06:10:34 -07:00
|
|
|
|
open_orders_address: PublicKey,
|
|
|
|
|
all_open_orders_addresses: typing.Sequence[PublicKey]
|
2021-08-24 12:13:44 -07:00
|
|
|
|
):
|
|
|
|
|
super().__init__()
|
2021-09-02 05:11:35 -07:00
|
|
|
|
self.order_owner: PublicKey = order_owner
|
2021-08-24 12:13:44 -07:00
|
|
|
|
self.market: mango.SpotMarket = market
|
|
|
|
|
self.oracle: mango.Oracle = oracle
|
|
|
|
|
|
|
|
|
|
self.group_address: PublicKey = group_address
|
2021-08-30 16:30:22 -07:00
|
|
|
|
self.cache_address: PublicKey = cache_address
|
2021-08-24 12:13:44 -07:00
|
|
|
|
self.account_address: PublicKey = account_address
|
|
|
|
|
self.open_orders_address: PublicKey = open_orders_address
|
2021-09-09 06:10:34 -07:00
|
|
|
|
self.all_open_orders_addresses: typing.Sequence[PublicKey] = all_open_orders_addresses
|
2021-08-24 12:13:44 -07:00
|
|
|
|
|
2021-10-04 10:27:07 -07:00
|
|
|
|
self.collateral_calculator: CollateralCalculator = SpotCollateralCalculator()
|
2021-08-30 16:30:22 -07:00
|
|
|
|
|
2021-08-24 12:13:44 -07:00
|
|
|
|
def poll(self, context: mango.Context) -> ModelState:
|
|
|
|
|
addresses: typing.List[PublicKey] = [
|
|
|
|
|
self.group_address,
|
2021-08-30 16:30:22 -07:00
|
|
|
|
self.cache_address,
|
2021-08-24 12:13:44 -07:00
|
|
|
|
self.account_address,
|
|
|
|
|
self.market.underlying_serum_market.state.bids(),
|
2021-09-09 06:10:34 -07:00
|
|
|
|
self.market.underlying_serum_market.state.asks(),
|
|
|
|
|
*self.all_open_orders_addresses
|
2021-08-24 12:13:44 -07:00
|
|
|
|
]
|
|
|
|
|
account_infos: typing.Sequence[mango.AccountInfo] = mango.AccountInfo.load_multiple(context, addresses)
|
|
|
|
|
group: mango.Group = mango.Group.parse(context, account_infos[0])
|
2021-08-30 16:30:22 -07:00
|
|
|
|
cache: mango.Cache = mango.Cache.parse(account_infos[1])
|
|
|
|
|
account: mango.Account = mango.Account.parse(account_infos[2], group)
|
2021-09-09 06:10:34 -07:00
|
|
|
|
|
|
|
|
|
# Update our stash of OpenOrders addresses for next time, in case new OpenOrders accounts were added
|
|
|
|
|
self.all_open_orders_addresses = list([oo for oo in account.spot_open_orders if oo is not None])
|
|
|
|
|
|
|
|
|
|
spot_open_orders_account_infos_by_address = {
|
|
|
|
|
str(account_info.address): account_info for account_info in account_infos[5:]}
|
|
|
|
|
|
|
|
|
|
all_open_orders: typing.Dict[str, mango.OpenOrders] = {}
|
|
|
|
|
for basket_token in account.basket:
|
|
|
|
|
if basket_token.spot_open_orders is not None and str(basket_token.spot_open_orders) in spot_open_orders_account_infos_by_address:
|
|
|
|
|
account_info: mango.AccountInfo = spot_open_orders_account_infos_by_address[str(
|
|
|
|
|
basket_token.spot_open_orders)]
|
|
|
|
|
open_orders: mango.OpenOrders = mango.OpenOrders.parse(
|
|
|
|
|
account_info,
|
|
|
|
|
basket_token.token_info.decimals,
|
|
|
|
|
account.shared_quote_token.token_info.token.decimals)
|
|
|
|
|
all_open_orders[str(basket_token.spot_open_orders)] = open_orders
|
|
|
|
|
|
|
|
|
|
placed_orders_container: mango.PlacedOrdersContainer = all_open_orders[str(self.open_orders_address)]
|
2021-08-24 12:13:44 -07:00
|
|
|
|
|
2021-08-27 12:37:23 -07:00
|
|
|
|
# Spot markets don't accrue MNGO liquidity incentives
|
2021-10-04 10:27:07 -07:00
|
|
|
|
mngo = group.find_token_info_by_symbol("MNGO").token
|
2021-08-27 12:37:23 -07:00
|
|
|
|
mngo_accrued: TokenValue = TokenValue(mngo, Decimal(0))
|
|
|
|
|
|
2021-08-24 12:13:44 -07:00
|
|
|
|
base_value = mango.TokenValue.find_by_symbol(account.net_assets, self.market.base.symbol)
|
|
|
|
|
quote_value = mango.TokenValue.find_by_symbol(account.net_assets, self.market.quote.symbol)
|
2021-08-30 16:30:22 -07:00
|
|
|
|
|
2021-10-04 10:27:07 -07:00
|
|
|
|
available_collateral: TokenValue = self.collateral_calculator.calculate(account, all_open_orders, group, cache)
|
2021-08-30 16:30:22 -07:00
|
|
|
|
inventory: mango.Inventory = mango.Inventory(mango.InventorySource.ACCOUNT,
|
|
|
|
|
mngo_accrued,
|
|
|
|
|
available_collateral,
|
|
|
|
|
base_value,
|
|
|
|
|
quote_value)
|
2021-08-24 12:13:44 -07:00
|
|
|
|
|
2021-09-30 10:53:33 -07:00
|
|
|
|
# Both these will have top-of-book at index 0.
|
2021-08-24 12:13:44 -07:00
|
|
|
|
bids: typing.Sequence[mango.Order] = mango.parse_account_info_to_orders(
|
2021-09-09 06:10:34 -07:00
|
|
|
|
account_infos[3], self.market.underlying_serum_market)
|
2021-08-30 16:30:22 -07:00
|
|
|
|
asks: typing.Sequence[mango.Order] = mango.parse_account_info_to_orders(
|
2021-09-09 06:10:34 -07:00
|
|
|
|
account_infos[4], self.market.underlying_serum_market)
|
2021-08-24 12:13:44 -07:00
|
|
|
|
|
|
|
|
|
price: mango.Price = self.oracle.fetch_price(context)
|
|
|
|
|
|
2021-09-02 05:11:35 -07:00
|
|
|
|
return self.from_values(self.order_owner, self.market, group, account, price, placed_orders_container, inventory, bids, asks)
|
2021-08-24 12:13:44 -07:00
|
|
|
|
|
|
|
|
|
def __str__(self) -> str:
|
|
|
|
|
return f"""« 𝚂𝚙𝚘𝚝𝙿𝚘𝚕𝚕𝚒𝚗𝚐𝙼𝚘𝚍𝚎𝚕𝚂𝚝𝚊𝚝𝚎𝙱𝚞𝚒𝚕𝚍𝚎𝚛 for market '{self.market.symbol}' »"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# # 🥭 PerpPollingModelStateBuilder class
|
|
|
|
|
#
|
|
|
|
|
# Polls Solana and builds a `ModelState` for a `PerpMarket`
|
|
|
|
|
#
|
|
|
|
|
class PerpPollingModelStateBuilder(PollingModelStateBuilder):
|
|
|
|
|
def __init__(self,
|
2021-09-02 05:11:35 -07:00
|
|
|
|
order_owner: PublicKey,
|
2021-08-24 12:13:44 -07:00
|
|
|
|
market: mango.PerpMarket,
|
|
|
|
|
oracle: mango.Oracle,
|
|
|
|
|
group_address: PublicKey,
|
2021-08-30 16:30:22 -07:00
|
|
|
|
cache_address: PublicKey,
|
2021-08-24 12:13:44 -07:00
|
|
|
|
account_address: PublicKey
|
|
|
|
|
):
|
|
|
|
|
super().__init__()
|
2021-09-02 05:11:35 -07:00
|
|
|
|
self.order_owner: PublicKey = order_owner
|
2021-08-24 12:13:44 -07:00
|
|
|
|
self.market: mango.PerpMarket = market
|
|
|
|
|
self.oracle: mango.Oracle = oracle
|
|
|
|
|
|
|
|
|
|
self.group_address: PublicKey = group_address
|
2021-08-30 16:30:22 -07:00
|
|
|
|
self.cache_address: PublicKey = cache_address
|
2021-08-24 12:13:44 -07:00
|
|
|
|
self.account_address: PublicKey = account_address
|
|
|
|
|
|
2021-10-04 10:27:07 -07:00
|
|
|
|
self.collateral_calculator: CollateralCalculator = PerpCollateralCalculator()
|
2021-08-30 16:30:22 -07:00
|
|
|
|
|
2021-08-24 12:13:44 -07:00
|
|
|
|
def poll(self, context: mango.Context) -> ModelState:
|
|
|
|
|
addresses: typing.List[PublicKey] = [
|
|
|
|
|
self.group_address,
|
2021-08-30 16:30:22 -07:00
|
|
|
|
self.cache_address,
|
2021-08-24 12:13:44 -07:00
|
|
|
|
self.account_address,
|
|
|
|
|
self.market.underlying_perp_market.bids,
|
|
|
|
|
self.market.underlying_perp_market.asks
|
|
|
|
|
]
|
|
|
|
|
account_infos: typing.Sequence[mango.AccountInfo] = mango.AccountInfo.load_multiple(context, addresses)
|
|
|
|
|
group: mango.Group = mango.Group.parse(context, account_infos[0])
|
2021-08-30 16:30:22 -07:00
|
|
|
|
cache: mango.Cache = mango.Cache.parse(account_infos[1])
|
|
|
|
|
account: mango.Account = mango.Account.parse(account_infos[2], group)
|
2021-08-24 12:13:44 -07:00
|
|
|
|
|
|
|
|
|
index = group.find_perp_market_index(self.market.address)
|
|
|
|
|
perp_account = account.perp_accounts[index]
|
|
|
|
|
if perp_account is None:
|
|
|
|
|
raise Exception(f"Could not find perp account at index {index} of account {account.address}.")
|
|
|
|
|
placed_orders_container: mango.PlacedOrdersContainer = perp_account.open_orders
|
|
|
|
|
|
|
|
|
|
base_lots = perp_account.base_position
|
2021-09-09 09:17:23 -07:00
|
|
|
|
base_value = self.market.lot_size_converter.base_size_lots_to_number(base_lots)
|
2021-08-24 12:13:44 -07:00
|
|
|
|
base_token_value = mango.TokenValue(self.market.base, base_value)
|
|
|
|
|
quote_token_value = mango.TokenValue.find_by_symbol(account.net_assets, self.market.quote.symbol)
|
2021-10-04 10:27:07 -07:00
|
|
|
|
available_collateral: TokenValue = self.collateral_calculator.calculate(account, {}, group, cache)
|
2021-08-30 16:30:22 -07:00
|
|
|
|
inventory: mango.Inventory = mango.Inventory(mango.InventorySource.ACCOUNT,
|
|
|
|
|
perp_account.mngo_accrued,
|
|
|
|
|
available_collateral,
|
|
|
|
|
base_token_value,
|
|
|
|
|
quote_token_value)
|
2021-08-24 12:13:44 -07:00
|
|
|
|
|
2021-09-30 10:53:33 -07:00
|
|
|
|
# Both these will have top-of-book at index 0.
|
2021-08-24 12:13:44 -07:00
|
|
|
|
bids: mango.PerpOrderBookSide = mango.PerpOrderBookSide.parse(
|
|
|
|
|
context, account_infos[3], self.market.underlying_perp_market)
|
2021-08-30 16:30:22 -07:00
|
|
|
|
asks: mango.PerpOrderBookSide = mango.PerpOrderBookSide.parse(
|
|
|
|
|
context, account_infos[4], self.market.underlying_perp_market)
|
2021-08-24 12:13:44 -07:00
|
|
|
|
|
|
|
|
|
price: mango.Price = self.oracle.fetch_price(context)
|
|
|
|
|
|
2021-09-02 05:11:35 -07:00
|
|
|
|
return self.from_values(self.order_owner, self.market, group, account, price, placed_orders_container, inventory, bids.orders(), asks.orders())
|
2021-08-24 12:13:44 -07:00
|
|
|
|
|
|
|
|
|
def __str__(self) -> str:
|
|
|
|
|
return f"""« 𝙿𝚎𝚛𝚙𝙿𝚘𝚕𝚕𝚒𝚗𝚐𝙼𝚘𝚍𝚎𝚕𝚂𝚝𝚊𝚝𝚎𝙱𝚞𝚒𝚕𝚍𝚎𝚛 for market '{self.market.symbol}' »"""
|