Some fixes for health calculations WIP.
This commit is contained in:
parent
95e2496ad3
commit
4a24f3df55
|
@ -71,10 +71,9 @@ for account in mango_accounts:
|
|||
report: mango.AccountTokenValues = mango.AccountTokenValues.from_account_basket_base_token(
|
||||
asset, open_orders, group)
|
||||
# print(report)
|
||||
market_cache: mango.MarketCache = group.market_cache_from_cache(cache, report.base_token)
|
||||
price_from_cache: mango.TokenValue = group.token_price_from_cache(cache, report.base_token)
|
||||
perp_market_cache: typing.Optional[mango.PerpMarketCache] = group.perp_market_cache_from_cache(
|
||||
cache, report.base_token)
|
||||
priced_report: mango.AccountTokenValues = report.priced(price_from_cache, perp_market_cache)
|
||||
priced_report: mango.AccountTokenValues = report.priced(market_cache)
|
||||
account_value += priced_report.net_value
|
||||
quote_token_free_in_open_orders += priced_report.quote_token_free
|
||||
quote_token_total_in_open_orders += priced_report.quote_token_total
|
||||
|
@ -82,7 +81,9 @@ for account in mango_accounts:
|
|||
|
||||
quote_report: mango.AccountTokenValues = mango.AccountTokenValues(account.shared_quote_token.token_info.token,
|
||||
account.shared_quote_token.token_info.token,
|
||||
account.shared_quote_token.raw_deposit,
|
||||
account.shared_quote_token.deposit,
|
||||
account.shared_quote_token.raw_borrow,
|
||||
account.shared_quote_token.borrow,
|
||||
mango.TokenValue(
|
||||
group.shared_quote_token.token, Decimal(0)),
|
||||
|
@ -92,7 +93,12 @@ for account in mango_accounts:
|
|||
quote_token_total_in_open_orders,
|
||||
mango.TokenValue(
|
||||
group.shared_quote_token.token, Decimal(0)),
|
||||
Decimal(0), Decimal(0), Decimal(0),
|
||||
Decimal(0), Decimal(0),
|
||||
mango.TokenValue(
|
||||
group.shared_quote_token.token, Decimal(0)),
|
||||
mango.TokenValue(
|
||||
group.shared_quote_token.token, Decimal(0)),
|
||||
Decimal(0), Decimal(0),
|
||||
mango.NullLotSizeConverter())
|
||||
account_value += quote_report.net_value + quote_token_total_in_open_orders
|
||||
print(quote_report)
|
||||
|
|
|
@ -8,7 +8,7 @@ from .accounttokenvalues import AccountTokenValues, PricedAccountTokenValues
|
|||
from .addressableaccount import AddressableAccount
|
||||
from .arguments import parse_args
|
||||
from .balancesheet import BalanceSheet
|
||||
from .cache import PriceCache, RootBankCache, PerpMarketCache, Cache
|
||||
from .cache import PriceCache, RootBankCache, PerpMarketCache, MarketCache, Cache
|
||||
from .client import ClientException, RateLimitException, TooMuchBandwidthRateLimitException, TooManyRequestsRateLimitException, BlockhashNotFoundException, NodeIsBehindException, FailedToFetchBlockhashException, TransactionException, CompatibleClient, BetterClient
|
||||
from .combinableinstructions import CombinableInstructions
|
||||
from .constants import SYSTEM_PROGRAM_ADDRESS, SOL_MINT_ADDRESS, SOL_DECIMALS, SOL_DECIMAL_DIVISOR, WARNING_DISCLAIMER_TEXT, MangoConstants
|
||||
|
|
|
@ -42,20 +42,26 @@ from .version import Version
|
|||
# `AccountBasketToken` gathers basket items together instead of separate arrays.
|
||||
#
|
||||
class AccountBasketToken:
|
||||
def __init__(self, token_info: TokenInfo, deposit: TokenValue, borrow: TokenValue):
|
||||
def __init__(self, token_info: TokenInfo, raw_deposit: Decimal, deposit: TokenValue, raw_borrow: Decimal, borrow: TokenValue):
|
||||
self.token_info: TokenInfo = token_info
|
||||
self.raw_deposit: Decimal = raw_deposit
|
||||
self.deposit: TokenValue = deposit
|
||||
self.raw_borrow: Decimal = raw_borrow
|
||||
self.borrow: TokenValue = borrow
|
||||
|
||||
@property
|
||||
def net_value(self) -> TokenValue:
|
||||
return self.deposit - self.borrow
|
||||
|
||||
@property
|
||||
def raw_net_value(self) -> Decimal:
|
||||
return self.raw_deposit - self.raw_borrow
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"""« 𝙰𝚌𝚌𝚘𝚞𝚗𝚝𝙱𝚊𝚜𝚔𝚎𝚝𝚃𝚘𝚔𝚎𝚗 {self.token_info.token.symbol}
|
||||
Net Value: {self.net_value}
|
||||
Deposited: {self.deposit}
|
||||
Borrowed: {self.borrow}
|
||||
Deposited: {self.deposit} (raw value: {self.raw_deposit})
|
||||
Borrowed: {self.borrow} (raw value {self.raw_borrow})
|
||||
»"""
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
@ -68,8 +74,8 @@ class AccountBasketToken:
|
|||
# account.
|
||||
#
|
||||
class AccountBasketBaseToken(AccountBasketToken):
|
||||
def __init__(self, token_info: TokenInfo, quote_token_info: TokenInfo, deposit: TokenValue, borrow: TokenValue, spot_open_orders: typing.Optional[PublicKey], perp_account: typing.Optional[PerpAccount]):
|
||||
super().__init__(token_info, deposit, borrow)
|
||||
def __init__(self, token_info: TokenInfo, quote_token_info: TokenInfo, raw_deposit: Decimal, deposit: TokenValue, raw_borrow: Decimal, borrow: TokenValue, spot_open_orders: typing.Optional[PublicKey], perp_account: typing.Optional[PerpAccount]):
|
||||
super().__init__(token_info, raw_deposit, deposit, raw_borrow, borrow)
|
||||
self.quote_token_info: TokenInfo = quote_token_info
|
||||
self.spot_open_orders: typing.Optional[PublicKey] = spot_open_orders
|
||||
self.perp_account: typing.Optional[PerpAccount] = perp_account
|
||||
|
@ -80,8 +86,8 @@ class AccountBasketBaseToken(AccountBasketToken):
|
|||
perp_account = f"{self.perp_account}".replace("\n", "\n ")
|
||||
return f"""« 𝙰𝚌𝚌𝚘𝚞𝚗𝚝𝙱𝚊𝚜𝚔𝚎𝚝𝙱𝚊𝚜𝚎𝚃𝚘𝚔𝚎𝚗 {self.token_info.token.symbol}
|
||||
Net Value: {self.net_value}
|
||||
Deposited: {self.deposit}
|
||||
Borrowed: {self.borrow}
|
||||
Deposited: {self.deposit} (raw value: {self.raw_deposit})
|
||||
Borrowed: {self.borrow} (raw value {self.raw_borrow})
|
||||
Spot OpenOrders: {self.spot_open_orders or "None"}
|
||||
Perp Account:
|
||||
{perp_account}
|
||||
|
@ -146,9 +152,11 @@ class Account(AddressableAccount):
|
|||
|
||||
for index, token_info in enumerate(group.tokens[:-1]):
|
||||
if token_info:
|
||||
intrinsic_deposit = token_info.root_bank.deposit_index * layout.deposits[index]
|
||||
raw_deposit: Decimal = layout.deposits[index]
|
||||
intrinsic_deposit = token_info.root_bank.deposit_index * raw_deposit
|
||||
deposit = TokenValue(token_info.token, token_info.token.shift_to_decimals(intrinsic_deposit))
|
||||
intrinsic_borrow = token_info.root_bank.borrow_index * layout.borrows[index]
|
||||
raw_borrow: Decimal = layout.borrows[index]
|
||||
intrinsic_borrow = token_info.root_bank.borrow_index * raw_borrow
|
||||
borrow = TokenValue(token_info.token, token_info.token.shift_to_decimals(intrinsic_borrow))
|
||||
perp_open_orders = PerpOpenOrders(placed_orders_all_markets[index])
|
||||
group_basket_market = group.markets[index]
|
||||
|
@ -163,19 +171,22 @@ class Account(AddressableAccount):
|
|||
mngo_token_info.token)
|
||||
spot_open_orders = layout.spot_open_orders[index]
|
||||
basket_item: AccountBasketBaseToken = AccountBasketBaseToken(
|
||||
token_info, quote_token_info, deposit, borrow, spot_open_orders, perp_account)
|
||||
token_info, quote_token_info, raw_deposit, deposit, raw_borrow, borrow, spot_open_orders, perp_account)
|
||||
basket += [basket_item]
|
||||
active_in_basket += [True]
|
||||
else:
|
||||
active_in_basket += [False]
|
||||
|
||||
intrinsic_quote_deposit = quote_token_info.root_bank.deposit_index * layout.deposits[-1]
|
||||
raw_quote_deposit: Decimal = layout.deposits[-1]
|
||||
intrinsic_quote_deposit = quote_token_info.root_bank.deposit_index * raw_quote_deposit
|
||||
quote_deposit = TokenValue(quote_token_info.token,
|
||||
quote_token_info.token.shift_to_decimals(intrinsic_quote_deposit))
|
||||
intrinsic_quote_borrow = quote_token_info.root_bank.borrow_index * layout.borrows[-1]
|
||||
raw_quote_borrow: Decimal = layout.borrows[-1]
|
||||
intrinsic_quote_borrow = quote_token_info.root_bank.borrow_index * raw_quote_borrow
|
||||
quote_borrow = TokenValue(quote_token_info.token,
|
||||
quote_token_info.token.shift_to_decimals(intrinsic_quote_borrow))
|
||||
quote: AccountBasketToken = AccountBasketToken(quote_token_info, quote_deposit, quote_borrow)
|
||||
quote: AccountBasketToken = AccountBasketToken(
|
||||
quote_token_info, raw_quote_deposit, quote_deposit, raw_quote_borrow, quote_borrow)
|
||||
|
||||
msrm_amount: Decimal = layout.msrm_amount
|
||||
being_liquidated: bool = bool(layout.being_liquidated)
|
||||
|
|
|
@ -18,7 +18,7 @@ import typing
|
|||
from decimal import Decimal
|
||||
|
||||
from .account import AccountBasketBaseToken
|
||||
from .cache import PerpMarketCache
|
||||
from .cache import PerpMarketCache, MarketCache
|
||||
from .calculators.unsettledfundingcalculator import calculate_unsettled_funding, UnsettledFundingParams
|
||||
from .group import Group
|
||||
from .lotsizeconverter import LotSizeConverter
|
||||
|
@ -55,10 +55,12 @@ def _token_values_from_open_orders(base_token: Token, quote_token: Token, spot_o
|
|||
# `AccountTokenValues` gathers basket items together instead of separate arrays.
|
||||
#
|
||||
class AccountTokenValues:
|
||||
def __init__(self, base_token: Token, quote_token: Token, deposit: TokenValue, borrow: TokenValue, base_token_free: TokenValue, base_token_total: TokenValue, quote_token_free: TokenValue, quote_token_total: TokenValue, perp_base_position: TokenValue, raw_perp_quote_position: Decimal, long_settled_funding: Decimal, short_settled_funding: Decimal, lot_size_converter: LotSizeConverter):
|
||||
def __init__(self, base_token: Token, quote_token: Token, raw_deposit: Decimal, deposit: TokenValue, raw_borrow: Decimal, borrow: TokenValue, base_token_free: TokenValue, base_token_total: TokenValue, quote_token_free: TokenValue, quote_token_total: TokenValue, perp_base_position: TokenValue, raw_perp_quote_position: Decimal, raw_taker_quote: Decimal, bids_quantity: TokenValue, asks_quantity: TokenValue, long_settled_funding: Decimal, short_settled_funding: Decimal, lot_size_converter: LotSizeConverter):
|
||||
self.base_token: Token = base_token
|
||||
self.quote_token: Token = quote_token
|
||||
self.raw_deposit: Decimal = raw_deposit
|
||||
self.deposit: TokenValue = deposit
|
||||
self.raw_borrow: Decimal = raw_borrow
|
||||
self.borrow: TokenValue = borrow
|
||||
|
||||
self.base_token_free: TokenValue = base_token_free
|
||||
|
@ -67,6 +69,9 @@ class AccountTokenValues:
|
|||
self.quote_token_total: TokenValue = quote_token_total
|
||||
self.perp_base_position: TokenValue = perp_base_position
|
||||
self.raw_perp_quote_position: Decimal = raw_perp_quote_position
|
||||
self.raw_taker_quote: Decimal = raw_taker_quote
|
||||
self.bids_quantity: TokenValue = bids_quantity
|
||||
self.asks_quantity: TokenValue = asks_quantity
|
||||
self.long_settled_funding: Decimal = long_settled_funding
|
||||
self.short_settled_funding: Decimal = short_settled_funding
|
||||
self.lot_size_converter: LotSizeConverter = lot_size_converter
|
||||
|
@ -83,8 +88,16 @@ class AccountTokenValues:
|
|||
def quote_token_locked(self) -> TokenValue:
|
||||
return self.quote_token_total - self.quote_token_free
|
||||
|
||||
def priced(self, price: TokenValue, perp_market_cache: typing.Optional[PerpMarketCache]) -> "PricedAccountTokenValues":
|
||||
return PricedAccountTokenValues(self, price, perp_market_cache)
|
||||
@property
|
||||
def if_all_bids_executed(self) -> TokenValue:
|
||||
return self.perp_base_position + self.bids_quantity
|
||||
|
||||
@property
|
||||
def if_all_asks_executed(self) -> TokenValue:
|
||||
return self.perp_base_position - self.asks_quantity
|
||||
|
||||
def priced(self, market_cache: MarketCache) -> "PricedAccountTokenValues":
|
||||
return PricedAccountTokenValues(self, market_cache)
|
||||
|
||||
@staticmethod
|
||||
def from_account_basket_base_token(account_basket_token: AccountBasketBaseToken, open_orders_by_address: typing.Dict[str, OpenOrders], group: Group) -> "AccountTokenValues":
|
||||
|
@ -106,16 +119,28 @@ class AccountTokenValues:
|
|||
long_settled_funding: Decimal = perp_account.long_settled_funding / lot_size_converter.quote_lot_size
|
||||
short_settled_funding: Decimal = perp_account.short_settled_funding / lot_size_converter.quote_lot_size
|
||||
|
||||
return AccountTokenValues(base_token, quote_token, account_basket_token.deposit, account_basket_token.borrow, base_token_free, base_token_total, quote_token_free, quote_token_total, perp_base_position, perp_quote_position, long_settled_funding, short_settled_funding, lot_size_converter)
|
||||
taker_quote: Decimal = perp_account.taker_quote * lot_size_converter.quote_lot_size
|
||||
bids_quantity: TokenValue = TokenValue(base_token, base_token.shift_to_decimals(
|
||||
perp_account.bids_quantity * lot_size_converter.base_lot_size))
|
||||
asks_quantity: TokenValue = TokenValue(base_token, base_token.shift_to_decimals(
|
||||
perp_account.asks_quantity * lot_size_converter.base_lot_size))
|
||||
|
||||
return AccountTokenValues(base_token, quote_token, account_basket_token.raw_deposit, account_basket_token.deposit, account_basket_token.raw_borrow, account_basket_token.borrow, base_token_free, base_token_total, quote_token_free, quote_token_total, perp_base_position, perp_quote_position, taker_quote, bids_quantity, asks_quantity, long_settled_funding, short_settled_funding, lot_size_converter)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"""« 𝙰𝚌𝚌𝚘𝚞𝚗𝚝𝚃𝚘𝚔𝚎𝚗𝚁𝚎𝚙𝚘𝚛𝚝 {self.base_token.symbol}
|
||||
Deposited: {self.deposit}
|
||||
Borrowed : {self.borrow}
|
||||
Deposited : {self.deposit}
|
||||
Borrowed : {self.borrow}
|
||||
Unsettled:
|
||||
Base : {self.base_token_total} ({self.base_token_free} free)
|
||||
Quote : {self.quote_token_total} ({self.quote_token_free} free)
|
||||
Net Value: {self.net_value}
|
||||
Base : {self.base_token_total} ({self.base_token_free} free)
|
||||
Quote : {self.quote_token_total} ({self.quote_token_free} free)
|
||||
Perp:
|
||||
Base : {self.perp_base_position}
|
||||
Quote : {self.raw_perp_quote_position}
|
||||
If Executed:
|
||||
All Bids : {self.if_all_bids_executed}
|
||||
All Asks : {self.if_all_asks_executed}
|
||||
Net Value : {self.net_value}
|
||||
»"""
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
@ -123,29 +148,45 @@ class AccountTokenValues:
|
|||
|
||||
|
||||
class PricedAccountTokenValues(AccountTokenValues):
|
||||
def __init__(self, original_account_token_values: AccountTokenValues, price: TokenValue, perp_market_cache: typing.Optional[PerpMarketCache]):
|
||||
deposit: TokenValue = original_account_token_values.deposit * price
|
||||
borrow: TokenValue = original_account_token_values.borrow * price
|
||||
def __init__(self, original_account_token_values: AccountTokenValues, market_cache: MarketCache):
|
||||
price: TokenValue = market_cache.adjusted_price(
|
||||
original_account_token_values.base_token, original_account_token_values.quote_token)
|
||||
|
||||
if market_cache.root_bank is None:
|
||||
raise Exception(f"No root bank for token {original_account_token_values.base_token} in {market_cache}")
|
||||
|
||||
deposit_value: Decimal = original_account_token_values.raw_deposit * market_cache.root_bank.deposit_index * price.value
|
||||
shifted_deposit_value: Decimal = original_account_token_values.quote_token.shift_to_decimals(deposit_value)
|
||||
deposit: TokenValue = TokenValue(original_account_token_values.quote_token, shifted_deposit_value)
|
||||
|
||||
borrow_value: Decimal = original_account_token_values.raw_borrow * market_cache.root_bank.borrow_index * price.value
|
||||
shifted_borrow_value: Decimal = original_account_token_values.quote_token.shift_to_decimals(borrow_value)
|
||||
borrow: TokenValue = TokenValue(original_account_token_values.quote_token, shifted_borrow_value)
|
||||
|
||||
base_token_free: TokenValue = original_account_token_values.base_token_free * price
|
||||
base_token_total: TokenValue = original_account_token_values.base_token_total * price
|
||||
|
||||
perp_base_position: TokenValue = original_account_token_values.perp_base_position * price
|
||||
|
||||
super().__init__(original_account_token_values.base_token, original_account_token_values.quote_token,
|
||||
deposit, borrow, base_token_free, base_token_total,
|
||||
original_account_token_values.raw_deposit, deposit,
|
||||
original_account_token_values.raw_borrow, borrow, base_token_free, base_token_total,
|
||||
original_account_token_values.quote_token_free,
|
||||
original_account_token_values.quote_token_total,
|
||||
perp_base_position, original_account_token_values.raw_perp_quote_position,
|
||||
original_account_token_values.raw_taker_quote,
|
||||
original_account_token_values.bids_quantity, original_account_token_values.asks_quantity,
|
||||
original_account_token_values.long_settled_funding, original_account_token_values.short_settled_funding,
|
||||
original_account_token_values.lot_size_converter)
|
||||
self.original_account_token_values: AccountTokenValues = original_account_token_values
|
||||
self.price: TokenValue = price
|
||||
self.perp_market_cache: typing.Optional[PerpMarketCache] = perp_market_cache
|
||||
perp_quote_position: TokenValue = TokenValue(original_account_token_values.quote_token, Decimal(0))
|
||||
if perp_market_cache is not None:
|
||||
self.perp_market_cache: typing.Optional[PerpMarketCache] = market_cache.perp_market
|
||||
perp_quote_position: TokenValue = TokenValue(
|
||||
original_account_token_values.quote_token, original_account_token_values.raw_perp_quote_position)
|
||||
if market_cache.perp_market is not None:
|
||||
original: AccountTokenValues = original_account_token_values
|
||||
long_funding: Decimal = perp_market_cache.long_funding / original.lot_size_converter.quote_lot_size
|
||||
short_funding: Decimal = perp_market_cache.short_funding / original.lot_size_converter.quote_lot_size
|
||||
long_funding: Decimal = market_cache.perp_market.long_funding / original.lot_size_converter.quote_lot_size
|
||||
short_funding: Decimal = market_cache.perp_market.short_funding / original.lot_size_converter.quote_lot_size
|
||||
unsettled_funding: TokenValue = calculate_unsettled_funding(UnsettledFundingParams(
|
||||
quote_token=original.quote_token,
|
||||
base_position=original.perp_base_position,
|
||||
|
@ -154,21 +195,45 @@ class PricedAccountTokenValues(AccountTokenValues):
|
|||
short_funding=short_funding,
|
||||
short_settled_funding=original.short_settled_funding
|
||||
))
|
||||
perp_quote_position += unsettled_funding
|
||||
perp_quote_position -= unsettled_funding
|
||||
|
||||
self.perp_quote_position: TokenValue = perp_quote_position
|
||||
|
||||
@property
|
||||
def if_all_bids_executed(self) -> TokenValue:
|
||||
return self.perp_base_position + (self.bids_quantity * self.price)
|
||||
|
||||
@property
|
||||
def if_all_asks_executed(self) -> TokenValue:
|
||||
return self.perp_base_position - (self.asks_quantity * self.price)
|
||||
|
||||
def if_worst_execution(self) -> typing.Tuple[TokenValue, TokenValue]:
|
||||
taker_quote: TokenValue = TokenValue(self.perp_quote_position.token, self.raw_taker_quote)
|
||||
# print("Quote calc", self.perp_quote_position, taker_quote, self.bids_quantity, self.price)
|
||||
|
||||
if abs(self.if_all_bids_executed.value) > abs(self.if_all_asks_executed.value):
|
||||
base_position = self.if_all_bids_executed
|
||||
quote_position = self.perp_quote_position + taker_quote - (self.bids_quantity * self.price)
|
||||
else:
|
||||
base_position = self.if_all_asks_executed
|
||||
quote_position = self.perp_quote_position + taker_quote + (self.asks_quantity * self.price)
|
||||
|
||||
return base_position, quote_position
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"""« 𝙿𝚛𝚒𝚌𝚎𝚍𝙰𝚌𝚌𝚘𝚞𝚗𝚝𝚃𝚘𝚔𝚎𝚗𝚅𝚊𝚕𝚞𝚎𝚜 {self.base_token.symbol} priced in {self.quote_token.symbol}
|
||||
Deposited: {self.original_account_token_values.deposit:<45} worth {self.deposit}
|
||||
Borrowed: {self.original_account_token_values.borrow:<45} worth {self.borrow}
|
||||
Deposited : {self.original_account_token_values.deposit:<45} worth {self.deposit}
|
||||
Borrowed : {self.original_account_token_values.borrow:<45} worth {self.borrow}
|
||||
Unsettled:
|
||||
Base : {self.original_account_token_values.base_token_total:<45} worth {self.base_token_total}
|
||||
Quote : {self.original_account_token_values.quote_token_total:<45} worth {self.quote_token_total}
|
||||
Base : {self.original_account_token_values.base_token_total:<45} worth {self.base_token_total}
|
||||
Quote : {self.original_account_token_values.quote_token_total:<45} worth {self.quote_token_total}
|
||||
Perp:
|
||||
Base : {self.original_account_token_values.perp_base_position:<45} worth {self.perp_base_position}
|
||||
Quote : {self.perp_quote_position:<45} worth {self.perp_quote_position}
|
||||
Net Value: {self.original_account_token_values.net_value:<45} worth {self.net_value}
|
||||
Base : {self.original_account_token_values.perp_base_position:<45} worth {self.perp_base_position}
|
||||
Quote : {self.perp_quote_position:<45} worth {self.perp_quote_position}
|
||||
If Executed:
|
||||
All Bids : {self.original_account_token_values.if_all_bids_executed:<45} worth {self.if_all_bids_executed}
|
||||
All Asks : {self.original_account_token_values.if_all_asks_executed:<45} worth {self.if_all_asks_executed}
|
||||
Net Value : {self.original_account_token_values.net_value:<45} worth {self.net_value}
|
||||
»"""
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
|
|
@ -24,15 +24,15 @@ from .addressableaccount import AddressableAccount
|
|||
from .context import Context
|
||||
from .layouts import layouts
|
||||
from .metadata import Metadata
|
||||
from .token import Token
|
||||
from .tokenvalue import TokenValue
|
||||
from .version import Version
|
||||
|
||||
|
||||
# # 🥭 NodeBank class
|
||||
# # 🥭 PriceCache class
|
||||
#
|
||||
# `NodeBank` stores details of deposits/borrows and vault.
|
||||
# `PriceCache` stores a cached price.
|
||||
#
|
||||
|
||||
|
||||
class PriceCache:
|
||||
def __init__(self, price: Decimal, last_update: datetime):
|
||||
self.price: Decimal = price
|
||||
|
@ -45,12 +45,16 @@ class PriceCache:
|
|||
return PriceCache(layout.price, layout.last_update)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"« 𝙿𝚛𝚒𝚌𝚎𝙲𝚊𝚌𝚑𝚎 [{self.last_update}] {self.price:,.8f} »"
|
||||
return f"« 𝙿𝚛𝚒𝚌𝚎𝙲𝚊𝚌𝚑𝚎 [{self.last_update}] {self.price:,.20f} »"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self}"
|
||||
|
||||
|
||||
# # 🥭 RootBankCache class
|
||||
#
|
||||
# `RootBankCache` stores cached details of deposits and borrows.
|
||||
#
|
||||
class RootBankCache:
|
||||
def __init__(self, deposit_index: Decimal, borrow_index: Decimal, last_update: datetime):
|
||||
self.deposit_index: Decimal = deposit_index
|
||||
|
@ -64,12 +68,16 @@ class RootBankCache:
|
|||
return RootBankCache(layout.deposit_index, layout.borrow_index, layout.last_update)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"« 𝚁𝚘𝚘𝚝𝙱𝚊𝚗𝚔𝙲𝚊𝚌𝚑𝚎 [{self.last_update}] {self.deposit_index:,.8f} / {self.borrow_index:,.8f} »"
|
||||
return f"« 𝚁𝚘𝚘𝚝𝙱𝚊𝚗𝚔𝙲𝚊𝚌𝚑𝚎 [{self.last_update}] {self.deposit_index:,.20f} / {self.borrow_index:,.20f} »"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self}"
|
||||
|
||||
|
||||
# # 🥭 PerpMarketCache class
|
||||
#
|
||||
# `PerpMarketCache` stores cached details of long and short funding.
|
||||
#
|
||||
class PerpMarketCache:
|
||||
def __init__(self, long_funding: Decimal, short_funding: Decimal, last_update: datetime):
|
||||
self.long_funding: Decimal = long_funding
|
||||
|
@ -83,7 +91,44 @@ class PerpMarketCache:
|
|||
return PerpMarketCache(layout.long_funding, layout.short_funding, layout.last_update)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"« 𝙿𝚎𝚛𝚙𝙼𝚊𝚛𝚔𝚎𝚝𝙲𝚊𝚌𝚑𝚎 [{self.last_update}] {self.long_funding:,.8f} / {self.short_funding:,.8f} »"
|
||||
return f"« 𝙿𝚎𝚛𝚙𝙼𝚊𝚛𝚔𝚎𝚝𝙲𝚊𝚌𝚑𝚎 [{self.last_update}] {self.long_funding:,.20f} / {self.short_funding:,.20f} »"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self}"
|
||||
|
||||
|
||||
# # 🥭 MarketCache class
|
||||
#
|
||||
# `MarketCache` stores cached details of price, root bank, and perp market, for a particular market.
|
||||
#
|
||||
class MarketCache:
|
||||
def __init__(self, price: typing.Optional[PriceCache], root_bank: typing.Optional[RootBankCache], perp_market: typing.Optional[PerpMarketCache]):
|
||||
self.price: typing.Optional[PriceCache] = price
|
||||
self.root_bank: typing.Optional[RootBankCache] = root_bank
|
||||
self.perp_market: typing.Optional[PerpMarketCache] = perp_market
|
||||
|
||||
def adjusted_price(self, token: Token, quote_token: Token) -> TokenValue:
|
||||
if token == quote_token:
|
||||
# The price of 1 unit of the shared quote token is always 1.
|
||||
return TokenValue(token, Decimal(1))
|
||||
|
||||
if self.price is None:
|
||||
raise Exception(f"Could not find price index of basket token {token.symbol}.")
|
||||
|
||||
price: Decimal = self.price.price
|
||||
decimals_difference = token.decimals - quote_token.decimals
|
||||
if decimals_difference != 0:
|
||||
adjustment = 10 ** decimals_difference
|
||||
price = price * adjustment
|
||||
|
||||
return TokenValue(quote_token, price)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"""« 𝙼𝚊𝚛𝚔𝚎𝚝𝙲𝚊𝚌𝚑𝚎
|
||||
{self.price}
|
||||
{self.root_bank}
|
||||
{self.perp_market}
|
||||
»"""
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self}"
|
||||
|
@ -93,7 +138,6 @@ class PerpMarketCache:
|
|||
#
|
||||
# `Cache` stores cache details of prices, root banks and perp markets.
|
||||
#
|
||||
|
||||
class Cache(AddressableAccount):
|
||||
def __init__(self, account_info: AccountInfo, version: Version, meta_data: Metadata,
|
||||
price_cache: typing.Sequence[typing.Optional[PriceCache]],
|
||||
|
@ -136,6 +180,9 @@ class Cache(AddressableAccount):
|
|||
raise Exception(f"Cache account not found at address '{address}'")
|
||||
return Cache.parse(account_info)
|
||||
|
||||
def market_cache_for_index(self, index: int) -> MarketCache:
|
||||
return MarketCache(self.price_cache[index], self.root_bank_cache[index], self.perp_market_cache[index])
|
||||
|
||||
def __str__(self) -> str:
|
||||
def _render_list(items, stub):
|
||||
rendered = []
|
||||
|
|
|
@ -23,7 +23,7 @@ from mango.perpmarketinfo import PerpMarketInfo
|
|||
|
||||
from ..account import Account, AccountBasketBaseToken
|
||||
from ..accounttokenvalues import AccountTokenValues, PricedAccountTokenValues
|
||||
from ..cache import Cache, PerpMarketCache
|
||||
from ..cache import Cache, MarketCache
|
||||
from ..context import Context
|
||||
from ..group import Group
|
||||
from ..lotsizeconverter import NullLotSizeConverter
|
||||
|
@ -112,10 +112,12 @@ class HealthCalculator:
|
|||
# if (asset.deposit.value != 0) or (asset.borrow.value != 0) or (asset.net_value.value != 0):
|
||||
report: AccountTokenValues = AccountTokenValues.from_account_basket_base_token(
|
||||
asset, open_orders_by_address, group)
|
||||
price: TokenValue = group.token_price_from_cache(cache, report.base_token)
|
||||
perp_market_cache: typing.Optional[PerpMarketCache] = group.perp_market_cache_from_cache(
|
||||
cache, report.base_token)
|
||||
priced_report: PricedAccountTokenValues = report.priced(price, perp_market_cache)
|
||||
# print("report", report)
|
||||
# price: TokenValue = group.token_price_from_cache(cache, report.base_token)
|
||||
market_cache: MarketCache = group.market_cache_from_cache(cache, report.base_token)
|
||||
# print("Market cache", market_cache)
|
||||
priced_report: PricedAccountTokenValues = report.priced(market_cache)
|
||||
# print("priced_report", priced_report)
|
||||
priced_reports += [priced_report]
|
||||
|
||||
quote_token_free_in_open_orders: TokenValue = TokenValue(group.shared_quote_token.token, Decimal(0))
|
||||
|
@ -123,20 +125,29 @@ class HealthCalculator:
|
|||
for priced_report in priced_reports:
|
||||
quote_token_free_in_open_orders += priced_report.quote_token_free
|
||||
quote_token_total_in_open_orders += priced_report.quote_token_total
|
||||
# print("quote_token_free_in_open_orders", quote_token_free_in_open_orders)
|
||||
# print("quote_token_total_in_open_orders", quote_token_total_in_open_orders)
|
||||
|
||||
quote_report: AccountTokenValues = AccountTokenValues(account.shared_quote_token.token_info.token,
|
||||
account.shared_quote_token.token_info.token,
|
||||
account.shared_quote_token.raw_deposit,
|
||||
account.shared_quote_token.deposit,
|
||||
account.shared_quote_token.raw_borrow,
|
||||
account.shared_quote_token.borrow,
|
||||
TokenValue(group.shared_quote_token.token, Decimal(0)),
|
||||
TokenValue(group.shared_quote_token.token, Decimal(0)),
|
||||
quote_token_free_in_open_orders,
|
||||
quote_token_total_in_open_orders,
|
||||
TokenValue(group.shared_quote_token.token, Decimal(0)),
|
||||
Decimal(0), Decimal(0), Decimal(0),
|
||||
Decimal(0), Decimal(0),
|
||||
TokenValue(group.shared_quote_token.token, Decimal(0)),
|
||||
TokenValue(group.shared_quote_token.token, Decimal(0)),
|
||||
Decimal(0), Decimal(0),
|
||||
NullLotSizeConverter())
|
||||
# print("quote_report", quote_report)
|
||||
|
||||
health: Decimal = quote_report.net_value.value
|
||||
# print("Health (start)", health)
|
||||
for priced_report in priced_reports:
|
||||
market_index = group.find_token_market_index(priced_report.base_token)
|
||||
spot_market: typing.Optional[SpotMarketInfo] = group.spot_markets[market_index]
|
||||
|
@ -147,8 +158,9 @@ class HealthCalculator:
|
|||
|
||||
spot_weight = spot_market.init_asset_weight if base_value > 0 else spot_market.init_liab_weight
|
||||
spot_health = base_value.value * spot_weight
|
||||
# print("Weights", base_value.value, "*", spot_weight, spot_health)
|
||||
|
||||
perp_base, _ = self._calculate_pessimistic_perp_value(priced_report)
|
||||
perp_base, perp_quote = priced_report.if_worst_execution()
|
||||
perp_market: typing.Optional[PerpMarketInfo] = group.perp_markets[market_index]
|
||||
perp_health: Decimal = Decimal(0)
|
||||
if perp_market is not None:
|
||||
|
@ -158,7 +170,12 @@ class HealthCalculator:
|
|||
health += spot_health
|
||||
health += perp_health
|
||||
health += quote_value.value
|
||||
health += perp_quote.value
|
||||
health += priced_report.raw_perp_quote_position
|
||||
# print("Health (now)", health, spot_health, perp_health, quote_value.value,
|
||||
# perp_quote.value, priced_report.raw_perp_quote_position)
|
||||
|
||||
# print("Health (returning)", health)
|
||||
|
||||
return health
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ from solana.publickey import PublicKey
|
|||
|
||||
from .accountinfo import AccountInfo
|
||||
from .addressableaccount import AddressableAccount
|
||||
from .cache import Cache, PriceCache, PerpMarketCache
|
||||
from .cache import Cache, PerpMarketCache, MarketCache
|
||||
from .context import Context
|
||||
from .layouts import layouts
|
||||
from .lotsizeconverter import LotSizeConverter, RaisingLotSizeConverter
|
||||
|
@ -275,26 +275,16 @@ class Group(AddressableAccount):
|
|||
raise Exception(f"Could not find token info for symbol '{symbol}' in group {self.address}")
|
||||
|
||||
def token_price_from_cache(self, cache: Cache, token: Token) -> TokenValue:
|
||||
if token == self.shared_quote_token.token:
|
||||
# The price of 1 unit of the shared quote token is always 1.
|
||||
return TokenValue(token, Decimal(1))
|
||||
|
||||
token_index: int = self.find_token_market_index(token)
|
||||
cached_price: typing.Optional[PriceCache] = cache.price_cache[token_index]
|
||||
if cached_price is None:
|
||||
raise Exception(f"Could not find price index of basket token {token.symbol}.")
|
||||
|
||||
price: Decimal = cached_price.price
|
||||
decimals_difference = token.decimals - self.shared_quote_token.decimals
|
||||
if decimals_difference != 0:
|
||||
adjustment = 10 ** decimals_difference
|
||||
price = price * adjustment
|
||||
|
||||
return TokenValue(self.shared_quote_token.token, price)
|
||||
market_cache: MarketCache = self.market_cache_from_cache(cache, token)
|
||||
return market_cache.adjusted_price(token, self.shared_quote_token.token)
|
||||
|
||||
def perp_market_cache_from_cache(self, cache: Cache, token: Token) -> typing.Optional[PerpMarketCache]:
|
||||
market_cache: MarketCache = self.market_cache_from_cache(cache, token)
|
||||
return market_cache.perp_market
|
||||
|
||||
def market_cache_from_cache(self, cache: Cache, token: Token) -> MarketCache:
|
||||
token_index: int = self.find_token_market_index(token)
|
||||
return cache.perp_market_cache[token_index]
|
||||
return cache.market_cache_for_index(token_index)
|
||||
|
||||
def fetch_balances(self, context: Context, root_address: PublicKey) -> typing.Sequence[TokenValue]:
|
||||
balances: typing.List[TokenValue] = []
|
||||
|
|
|
@ -175,8 +175,8 @@ class FloatI80F48Adapter(construct.Adapter):
|
|||
|
||||
def _decode(self, obj, context, path) -> Decimal:
|
||||
# How many decimal places precision should we allow for an I80F48? We could:
|
||||
# return round(Decimal(obj) / self.divisor, 12)
|
||||
return Decimal(obj) / self.divisor
|
||||
return round(Decimal(obj) / self.divisor, 20)
|
||||
# return Decimal(obj) / self.divisor
|
||||
|
||||
def _encode(self, obj, context, path) -> bytes:
|
||||
return bytes(obj)
|
||||
|
|
|
@ -41,7 +41,7 @@ class Token:
|
|||
def shift_to_decimals(self, value: Decimal) -> Decimal:
|
||||
divisor = Decimal(10 ** self.decimals)
|
||||
shifted = value / divisor
|
||||
return round(shifted, int(self.decimals))
|
||||
return shifted
|
||||
|
||||
def shift_to_native(self, value: Decimal) -> Decimal:
|
||||
multiplier = Decimal(10 ** self.decimals)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from ..fakes import fake_context
|
||||
from ..data import load_data_from_directory
|
||||
from ..data import load_cache, load_data_from_directory
|
||||
|
||||
from decimal import Decimal
|
||||
from mango.calculators.healthcalculator import HealthType, HealthCalculator
|
||||
|
@ -15,15 +15,26 @@ def test_empty():
|
|||
assert health == Decimal("0")
|
||||
|
||||
|
||||
def test_1deposit():
|
||||
context = fake_context()
|
||||
group, cache, account, open_orders = load_data_from_directory("tests/testdata/1deposit")
|
||||
|
||||
actual = HealthCalculator(context, HealthType.INITIAL)
|
||||
health = actual.calculate(account, open_orders, group, cache)
|
||||
# Typescript says: 37904260000.05905822642118252475
|
||||
assert health == Decimal("37904.2600000591928892771752953600134")
|
||||
|
||||
|
||||
def test_perp_account_no_spot_openorders():
|
||||
context = fake_context()
|
||||
group, cache, account, open_orders = load_data_from_directory("tests/testdata/perp_account_no_spot_openorders")
|
||||
|
||||
actual = HealthCalculator(context, HealthType.INITIAL)
|
||||
health = actual.calculate(account, open_orders, group, cache)
|
||||
|
||||
# Typescript says: 341025333625.51856223547208912805
|
||||
# TODO: This is significantly different from Typescript answer
|
||||
assert health == Decimal("358923.807024760000053942349040880810")
|
||||
assert health == Decimal("7036880.69722811087924538653007346763")
|
||||
|
||||
|
||||
def test_perp_account_no_spot_openorders_unhealthy():
|
||||
|
@ -35,7 +46,7 @@ def test_perp_account_no_spot_openorders_unhealthy():
|
|||
health = actual.calculate(account, open_orders, group, cache)
|
||||
# Typescript says: -848086876487.04950427436299875694
|
||||
# TODO: This is significantly different from Typescript answer
|
||||
assert health == Decimal("-183567.651235339999859541052273925740")
|
||||
assert health == Decimal("1100318.49506000114695611699892507857")
|
||||
|
||||
|
||||
def test_account1():
|
||||
|
@ -46,7 +57,7 @@ def test_account1():
|
|||
health = actual.calculate(account, open_orders, group, cache)
|
||||
# Typescript says: 454884281.15520619643754685058
|
||||
# TODO: This is slightly different from Typescript answer
|
||||
assert health == Decimal("455.035346700961950901638175537300417")
|
||||
assert health == Decimal("2578453.62441460502856112835667758626")
|
||||
|
||||
|
||||
def test_account2():
|
||||
|
@ -57,4 +68,4 @@ def test_account2():
|
|||
health = actual.calculate(account, open_orders, group, cache)
|
||||
# Typescript says: 7516159604.84918334545095675026
|
||||
# TODO: This is slightly different from Typescript answer
|
||||
assert health == Decimal("7518.40764303100646658275181266617450")
|
||||
assert health == Decimal("-34471.8824121736505777079119365978915")
|
||||
|
|
|
@ -13,21 +13,30 @@ def test_construction():
|
|||
info = "some name"
|
||||
in_margin_basket = [False, False, False, False, False]
|
||||
active_in_basket = [False, True, False, True, True]
|
||||
quote_deposit = fake_token_value(Decimal(50))
|
||||
quote_borrow = fake_token_value(Decimal(5))
|
||||
quote = mango.AccountBasketToken(fake_token_info(), quote_deposit, quote_borrow)
|
||||
deposit1 = fake_token_value(Decimal(1))
|
||||
deposit2 = fake_token_value(Decimal(2))
|
||||
deposit3 = fake_token_value(Decimal(3))
|
||||
borrow1 = fake_token_value(Decimal("0.1"))
|
||||
borrow2 = fake_token_value(Decimal("0.2"))
|
||||
borrow3 = fake_token_value(Decimal("0.3"))
|
||||
raw_quote_deposit = Decimal(50)
|
||||
quote_deposit = fake_token_value(raw_quote_deposit)
|
||||
raw_quote_borrow = Decimal(5)
|
||||
quote_borrow = fake_token_value(raw_quote_borrow)
|
||||
quote = mango.AccountBasketToken(fake_token_info(), raw_quote_deposit,
|
||||
quote_deposit, raw_quote_borrow, quote_borrow)
|
||||
raw_deposit1 = Decimal(1)
|
||||
deposit1 = fake_token_value(raw_deposit1)
|
||||
raw_deposit2 = Decimal(2)
|
||||
deposit2 = fake_token_value(raw_deposit2)
|
||||
raw_deposit3 = Decimal(3)
|
||||
deposit3 = fake_token_value(raw_deposit3)
|
||||
raw_borrow1 = Decimal("0.1")
|
||||
borrow1 = fake_token_value(raw_borrow1)
|
||||
raw_borrow2 = Decimal("0.2")
|
||||
borrow2 = fake_token_value(raw_borrow2)
|
||||
raw_borrow3 = Decimal("0.3")
|
||||
borrow3 = fake_token_value(raw_borrow3)
|
||||
basket = [
|
||||
mango.AccountBasketBaseToken(fake_token_info(), fake_token_info(), deposit1, borrow1,
|
||||
mango.AccountBasketBaseToken(fake_token_info(), fake_token_info(), raw_deposit1, deposit1, raw_borrow1, borrow1,
|
||||
fake_seeded_public_key("spot openorders 1"), fake_seeded_public_key("perp1")),
|
||||
mango.AccountBasketBaseToken(fake_token_info(), fake_token_info(), deposit2, borrow2,
|
||||
mango.AccountBasketBaseToken(fake_token_info(), fake_token_info(), raw_deposit2, deposit2, raw_borrow2, borrow2,
|
||||
fake_seeded_public_key("spot openorders 2"), fake_seeded_public_key("perp2")),
|
||||
mango.AccountBasketBaseToken(fake_token_info(), fake_token_info(), deposit3, borrow3,
|
||||
mango.AccountBasketBaseToken(fake_token_info(), fake_token_info(), raw_deposit3, deposit3, raw_borrow3, borrow3,
|
||||
fake_seeded_public_key("spot openorders 3"), fake_seeded_public_key("perp3")),
|
||||
]
|
||||
msrm_amount = Decimal(0)
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
from .context import mango
|
||||
from .fakes import fake_account_info, fake_seeded_public_key
|
||||
from .data import load_cache
|
||||
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
|
||||
|
||||
def test_cache_constructor():
|
||||
account_info = fake_account_info(fake_seeded_public_key("cache"))
|
||||
meta_data = mango.Metadata(mango.layouts.DATA_TYPE.parse(bytearray(b'\x07')), mango.Version.V1, True)
|
||||
timestamp = datetime.now()
|
||||
price_cache = [mango.PriceCache(Decimal(26), timestamp)]
|
||||
root_bank_cache = [mango.RootBankCache(Decimal("0.00001"), Decimal("0.00001"), timestamp)]
|
||||
perp_market_cache = [mango.PerpMarketCache(Decimal("0.00002"), Decimal("0.00002"), timestamp)]
|
||||
actual = mango.Cache(account_info, mango.Version.V1, meta_data, price_cache, root_bank_cache, perp_market_cache)
|
||||
|
||||
assert actual is not None
|
||||
assert actual.logger is not None
|
||||
assert actual.account_info == account_info
|
||||
assert actual.address == fake_seeded_public_key("cache")
|
||||
assert actual.meta_data == meta_data
|
||||
assert actual.meta_data.data_type == mango.layouts.DATA_TYPE.Cache
|
||||
assert actual.price_cache == price_cache
|
||||
assert actual.root_bank_cache == root_bank_cache
|
||||
assert actual.perp_market_cache == perp_market_cache
|
||||
|
||||
|
||||
def test_load_cache():
|
||||
cache = load_cache("tests/testdata/1deposit/cache.json")
|
||||
|
||||
#
|
||||
# These values are all verified with the same file loaded in the TypeScript client.
|
||||
#
|
||||
|
||||
assert cache.price_cache[0].price == Decimal("0.33642499999999841975")
|
||||
assert cache.price_cache[1].price == Decimal("47380.32499999999999928946")
|
||||
assert cache.price_cache[2].price == Decimal("3309.69549999999999911893")
|
||||
assert cache.price_cache[3].price == Decimal("0.17261599999999788224")
|
||||
assert cache.price_cache[4].price == Decimal("8.79379999999999739657")
|
||||
assert cache.price_cache[5].price == Decimal("1")
|
||||
assert cache.price_cache[6].price == Decimal("1.00039999999999906777")
|
||||
assert cache.price_cache[7] is None
|
||||
assert cache.price_cache[8] is None
|
||||
assert cache.price_cache[9] is None
|
||||
assert cache.price_cache[10] is None
|
||||
assert cache.price_cache[11] is None
|
||||
assert cache.price_cache[12] is None
|
||||
assert cache.price_cache[13] is None
|
||||
assert cache.price_cache[14] is None
|
||||
|
||||
assert cache.root_bank_cache[0].deposit_index == Decimal("1001923.86460821722014813417")
|
||||
assert cache.root_bank_cache[0].borrow_index == Decimal("1002515.45257855337824182129")
|
||||
assert cache.root_bank_cache[1].deposit_index == Decimal("1000007.37249653914441083202")
|
||||
assert cache.root_bank_cache[1].borrow_index == Decimal("1000166.98522159213999316307")
|
||||
assert cache.root_bank_cache[2].deposit_index == Decimal("1000000.19554886875829424753")
|
||||
assert cache.root_bank_cache[2].borrow_index == Decimal("1000001.13273253565107623331")
|
||||
assert cache.root_bank_cache[3].deposit_index == Decimal("1000037.82149923799070379005")
|
||||
assert cache.root_bank_cache[3].borrow_index == Decimal("1000044.28925241010965052624")
|
||||
assert cache.root_bank_cache[4].deposit_index == Decimal("1000000.0000132182767842437")
|
||||
assert cache.root_bank_cache[4].borrow_index == Decimal("1000000.14235973938041368569")
|
||||
assert cache.root_bank_cache[5].deposit_index == Decimal("1000000.35244386506945346582")
|
||||
assert cache.root_bank_cache[5].borrow_index == Decimal("1000000.66156146420993522383")
|
||||
assert cache.root_bank_cache[6].deposit_index == Decimal("1000473.25161608998580575758")
|
||||
assert cache.root_bank_cache[6].borrow_index == Decimal("1000524.37279217702128875089")
|
||||
assert cache.root_bank_cache[7] is None
|
||||
assert cache.root_bank_cache[7] is None
|
||||
assert cache.root_bank_cache[8] is None
|
||||
assert cache.root_bank_cache[8] is None
|
||||
assert cache.root_bank_cache[9] is None
|
||||
assert cache.root_bank_cache[9] is None
|
||||
assert cache.root_bank_cache[10] is None
|
||||
assert cache.root_bank_cache[10] is None
|
||||
assert cache.root_bank_cache[11] is None
|
||||
assert cache.root_bank_cache[11] is None
|
||||
assert cache.root_bank_cache[12] is None
|
||||
assert cache.root_bank_cache[12] is None
|
||||
assert cache.root_bank_cache[13] is None
|
||||
assert cache.root_bank_cache[13] is None
|
||||
assert cache.root_bank_cache[14] is None
|
||||
assert cache.root_bank_cache[14] is None
|
||||
assert cache.root_bank_cache[15].deposit_index == Decimal("1000154.42276607534055088422")
|
||||
assert cache.root_bank_cache[15].borrow_index == Decimal("1000219.00868743509063563124")
|
||||
|
||||
assert cache.perp_market_cache[0] is None
|
||||
assert cache.perp_market_cache[1].long_funding == Decimal("-751864.70031280454435673732")
|
||||
assert cache.perp_market_cache[1].short_funding == Decimal("-752275.3557979761382519257")
|
||||
assert cache.perp_market_cache[2].long_funding == Decimal("0")
|
||||
assert cache.perp_market_cache[2].short_funding == Decimal("0")
|
||||
assert cache.perp_market_cache[3].long_funding == Decimal("-636425.51790158202868497028")
|
||||
assert cache.perp_market_cache[3].short_funding == Decimal("-636425.51790158202868497028")
|
||||
assert cache.perp_market_cache[4] is None
|
||||
assert cache.perp_market_cache[5] is None
|
||||
assert cache.perp_market_cache[6] is None
|
||||
assert cache.perp_market_cache[7] is None
|
||||
assert cache.perp_market_cache[8] is None
|
||||
assert cache.perp_market_cache[9] is None
|
||||
assert cache.perp_market_cache[10] is None
|
||||
assert cache.perp_market_cache[11] is None
|
||||
assert cache.perp_market_cache[12] is None
|
||||
assert cache.perp_market_cache[13] is None
|
||||
assert cache.perp_market_cache[14] is None
|
|
@ -54,8 +54,8 @@ def test_root_bank_constructor():
|
|||
assert actual.last_updated == timestamp
|
||||
|
||||
|
||||
def test_root_bank_loaded():
|
||||
actual = load_root_bank("tests/testdata/empty/root_bank0.json")
|
||||
def test_load_root_bank():
|
||||
actual = load_root_bank("tests/testdata/1deposit/root_bank0.json")
|
||||
|
||||
assert actual is not None
|
||||
assert actual.logger is not None
|
||||
|
@ -63,16 +63,10 @@ def test_root_bank_loaded():
|
|||
assert actual.meta_data.version == mango.Version.V1
|
||||
assert actual.meta_data.data_type == mango.layouts.DATA_TYPE.RootBank
|
||||
assert actual.meta_data.is_initialized
|
||||
# Typescript says: 0.69999999999999928946
|
||||
assert actual.optimal_util == Decimal("0.699999999999999289457264239899814129")
|
||||
# Typescript says: 0.05999999999999872102
|
||||
assert actual.optimal_rate == Decimal("0.0599999999999987210230756318196654320")
|
||||
# Typescript says: 1.5
|
||||
assert actual.optimal_util == Decimal("0.69999999999999928946")
|
||||
assert actual.optimal_rate == Decimal("0.05999999999999872102")
|
||||
assert actual.max_rate == Decimal("1.5")
|
||||
assert actual.node_banks[0] == PublicKey("J2Lmnc1e4frMnBEJARPoHtfpcohLfN67HdK1inXjTFSM")
|
||||
# Typescript says: 1000154.42276607355830719825
|
||||
assert actual.deposit_index == Decimal("1000154.42276607355830719825462438166")
|
||||
# Typescript says: 1000219.00867863010088498754
|
||||
assert actual.borrow_index == Decimal("1000219.00867863010088498754157626536")
|
||||
# Typescript says: "Mon, 04 Oct 2021 14:58:05 GMT"
|
||||
assert actual.deposit_index == Decimal("1000154.42276607355830719825")
|
||||
assert actual.borrow_index == Decimal("1000219.00867863010088498754")
|
||||
assert actual.last_updated == datetime(2021, 10, 4, 14, 58, 5, 0, timezone.utc)
|
||||
|
|
Loading…
Reference in New Issue