Tidied up reporting of balances before and after a liquidation.

This commit is contained in:
Geoff Taylor 2021-05-10 14:20:08 +01:00
parent b452887c28
commit fb52fe3671
4 changed files with 173 additions and 86 deletions

View File

@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
"id": "close-ideal",
"id": "intensive-intellectual",
"metadata": {},
"source": [
"# ⚠ Warning\n",
@ -16,7 +16,7 @@
},
{
"cell_type": "markdown",
"id": "pressed-merit",
"id": "secondary-birmingham",
"metadata": {},
"source": [
"# 🥭 BaseModel\n",
@ -33,7 +33,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "compliant-forth",
"id": "statewide-batman",
"metadata": {
"jupyter": {
"source_hidden": true
@ -55,14 +55,14 @@
"from solana.rpc.commitment import Single\n",
"from solana.rpc.types import MemcmpOpts\n",
"\n",
"from Constants import NUM_MARKETS, NUM_TOKENS, SYSTEM_PROGRAM_ADDRESS\n",
"from Constants import NUM_MARKETS, NUM_TOKENS, SOL_DECIMALS, SYSTEM_PROGRAM_ADDRESS\n",
"from Context import AccountInfo, Context\n",
"from Decoder import encode_key\n"
]
},
{
"cell_type": "markdown",
"id": "noted-elevation",
"id": "apart-rings",
"metadata": {},
"source": [
"## Version enum\n",
@ -73,7 +73,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "applicable-relative",
"id": "demanding-gallery",
"metadata": {},
"outputs": [],
"source": [
@ -88,7 +88,7 @@
},
{
"cell_type": "markdown",
"id": "prerequisite-representation",
"id": "miniature-malawi",
"metadata": {},
"source": [
"## SerumAccountFlags class\n",
@ -99,7 +99,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "marked-stretch",
"id": "christian-bonus",
"metadata": {},
"outputs": [],
"source": [
@ -142,7 +142,7 @@
},
{
"cell_type": "markdown",
"id": "grand-english",
"id": "described-structure",
"metadata": {},
"source": [
"## MangoAccountFlags class\n",
@ -153,7 +153,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "passive-litigation",
"id": "democratic-insider",
"metadata": {},
"outputs": [],
"source": [
@ -187,7 +187,7 @@
},
{
"cell_type": "markdown",
"id": "theoretical-hands",
"id": "accepting-science",
"metadata": {},
"source": [
"## Index class"
@ -196,7 +196,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "surprised-harrison",
"id": "essential-hawaiian",
"metadata": {},
"outputs": [],
"source": [
@ -223,7 +223,7 @@
},
{
"cell_type": "markdown",
"id": "integrated-xerox",
"id": "laden-bench",
"metadata": {},
"source": [
"## AggregatorConfig class"
@ -232,7 +232,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "floppy-spray",
"id": "threaded-wheat",
"metadata": {},
"outputs": [],
"source": [
@ -265,7 +265,7 @@
},
{
"cell_type": "markdown",
"id": "fresh-batch",
"id": "fixed-cocktail",
"metadata": {},
"source": [
"## Round class"
@ -274,7 +274,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "offensive-hygiene",
"id": "collect-influence",
"metadata": {},
"outputs": [],
"source": [
@ -299,7 +299,7 @@
},
{
"cell_type": "markdown",
"id": "turned-publisher",
"id": "nuclear-radio",
"metadata": {},
"source": [
"## Answer class"
@ -308,7 +308,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "optimum-exhibit",
"id": "described-maryland",
"metadata": {},
"outputs": [],
"source": [
@ -334,7 +334,7 @@
},
{
"cell_type": "markdown",
"id": "engaged-moderator",
"id": "impressive-poetry",
"metadata": {},
"source": [
"## Aggregator class"
@ -343,7 +343,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "textile-charge",
"id": "ongoing-running",
"metadata": {},
"outputs": [],
"source": [
@ -410,7 +410,7 @@
},
{
"cell_type": "markdown",
"id": "flush-biography",
"id": "promotional-truck",
"metadata": {},
"source": [
"## BasketTokenMetadata class\n"
@ -419,7 +419,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "responsible-throat",
"id": "portuguese-zimbabwe",
"metadata": {},
"outputs": [],
"source": [
@ -454,7 +454,27 @@
},
{
"cell_type": "markdown",
"id": "three-consolidation",
"id": "understanding-banks",
"metadata": {},
"source": [
"## SolBasketTokenMetadata object\n",
"\n",
"It's sometimes handy to have a BasketTokenMetadata for SOL, but SOL isn't actually a token and can't appear in baskets. This object defines a special case for SOL."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "parliamentary-retro",
"metadata": {},
"outputs": [],
"source": [
"SolBasketTokenMetadata = BasketTokenMetadata(\"SOL\", SYSTEM_PROGRAM_ADDRESS, SOL_DECIMALS, SYSTEM_PROGRAM_ADDRESS, Index(Version.UNSPECIFIED, datetime.datetime.now(), Decimal(0), Decimal(0)))"
]
},
{
"cell_type": "markdown",
"id": "understood-translator",
"metadata": {},
"source": [
"## TokenValue class\n",
@ -465,7 +485,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "stupid-device",
"id": "soviet-dance",
"metadata": {},
"outputs": [],
"source": [
@ -474,6 +494,32 @@
" self.token = token\n",
" self.value = value\n",
"\n",
" @staticmethod\n",
" def report(reporter: typing.Callable[[str], None], values: typing.List[\"TokenValue\"]) -> None:\n",
" for value in values:\n",
" reporter(f\"{value.value:>18,.8f} {value.token.name}\")\n",
"\n",
" @staticmethod\n",
" def find(values: typing.List[\"TokenValue\"], token: BasketTokenMetadata) -> \"TokenValue\":\n",
" found = [value for value in values if value.token == token]\n",
" if len(found) == 0:\n",
" raise Exception(f\"Token '{token.name}' not found in token values: {values}\")\n",
"\n",
" if len(found) > 1:\n",
" raise Exception(f\"Token '{token.name}' matched multiple tokens in values: {values}\")\n",
"\n",
" return found[0]\n",
"\n",
" @staticmethod\n",
" def changes(before: typing.List[\"TokenValue\"], after: typing.List[\"TokenValue\"]) -> typing.List[\"TokenValue\"]:\n",
" changes: typing.List[TokenValue] = []\n",
" for before_balance in before:\n",
" after_balance = TokenValue.find(after, before_balance.token)\n",
" result = TokenValue(before_balance.token, after_balance.value - before_balance.value)\n",
" changes += [result]\n",
"\n",
" return changes\n",
"\n",
" def __str__(self) -> str:\n",
" return f\"« TokenValue: {self.value:>18,.8f} {self.token.name} »\"\n",
"\n",
@ -483,7 +529,7 @@
},
{
"cell_type": "markdown",
"id": "stable-canal",
"id": "affiliated-thermal",
"metadata": {},
"source": [
"## MarketMetadata class"
@ -492,7 +538,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "welcome-hudson",
"id": "residential-awareness",
"metadata": {},
"outputs": [],
"source": [
@ -528,7 +574,7 @@
},
{
"cell_type": "markdown",
"id": "dimensional-static",
"id": "technical-hormone",
"metadata": {},
"source": [
"## Group class"
@ -537,7 +583,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "searching-marsh",
"id": "hidden-infrared",
"metadata": {},
"outputs": [],
"source": [
@ -627,6 +673,16 @@
" token_prices += [TokenValue(self.tokens[index], price)]\n",
" return token_prices\n",
"\n",
" def fetch_balances(self, root_address: PublicKey) -> typing.List[TokenValue]:\n",
" balances: typing.List[TokenValue] = []\n",
" sol_balance = self.context.fetch_sol_balance(root_address)\n",
" balances += [TokenValue(SolBasketTokenMetadata, sol_balance)]\n",
"\n",
" for token in self.tokens:\n",
" balance = self.context.fetch_token_balance(root_address, token.mint)\n",
" balances += [TokenValue(token, balance)]\n",
" return balances\n",
"\n",
" def index_of_token(self, token: BasketTokenMetadata) -> int:\n",
" for index, existing in enumerate(self.tokens):\n",
" if existing.mint == token.mint:\n",
@ -678,7 +734,7 @@
},
{
"cell_type": "markdown",
"id": "intermediate-storage",
"id": "earlier-brook",
"metadata": {},
"source": [
"## TokenAccount class"
@ -687,7 +743,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "unauthorized-cheese",
"id": "hindu-kingston",
"metadata": {},
"outputs": [],
"source": [
@ -728,7 +784,7 @@
},
{
"cell_type": "markdown",
"id": "continuous-palestine",
"id": "modular-candidate",
"metadata": {},
"source": [
"## OpenOrders class\n"
@ -737,7 +793,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "suffering-compilation",
"id": "incorporate-uganda",
"metadata": {},
"outputs": [],
"source": [
@ -871,7 +927,7 @@
},
{
"cell_type": "markdown",
"id": "frequent-raleigh",
"id": "structured-viewer",
"metadata": {},
"source": [
"## BalanceSheet class"
@ -880,7 +936,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "paperback-google",
"id": "engaged-quality",
"metadata": {},
"outputs": [],
"source": [
@ -927,7 +983,7 @@
},
{
"cell_type": "markdown",
"id": "enormous-spiritual",
"id": "induced-bolivia",
"metadata": {},
"source": [
"## MarginAccount class\n"
@ -936,7 +992,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "historic-photograph",
"id": "labeled-divide",
"metadata": {},
"outputs": [],
"source": [
@ -1133,7 +1189,7 @@
},
{
"cell_type": "markdown",
"id": "possible-round",
"id": "later-contribution",
"metadata": {},
"source": [
"# MarginAccountMetadata class"
@ -1142,7 +1198,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "engaged-patch",
"id": "composed-amendment",
"metadata": {},
"outputs": [],
"source": [
@ -1168,7 +1224,7 @@
},
{
"cell_type": "markdown",
"id": "floating-america",
"id": "colonial-association",
"metadata": {},
"source": [
"# 🏃 Running"
@ -1177,7 +1233,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "professional-bulgaria",
"id": "thousand-madrid",
"metadata": {},
"outputs": [],
"source": [

View File

@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
"id": "agreed-miniature",
"id": "incident-square",
"metadata": {},
"source": [
"# ⚠ Warning\n",
@ -16,7 +16,7 @@
},
{
"cell_type": "markdown",
"id": "empty-academy",
"id": "wooden-alignment",
"metadata": {},
"source": [
"# 🥭 Constants\n",
@ -27,7 +27,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "approximate-creation",
"id": "silent-exercise",
"metadata": {
"jupyter": {
"source_hidden": true
@ -44,7 +44,7 @@
},
{
"cell_type": "markdown",
"id": "international-purple",
"id": "cathedral-government",
"metadata": {},
"source": [
"## SYSTEM_PROGRAM_ADDRESS\n",
@ -55,7 +55,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "noted-grass",
"id": "interpreted-adjustment",
"metadata": {},
"outputs": [],
"source": [
@ -64,7 +64,27 @@
},
{
"cell_type": "markdown",
"id": "overhead-wallace",
"id": "martial-reason",
"metadata": {},
"source": [
"# SOL_DECIMALS\n",
"\n",
"The number of decimal places used to convert Lamports into SOLs."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "spatial-spencer",
"metadata": {},
"outputs": [],
"source": [
"SOL_DECIMALS = 9"
]
},
{
"cell_type": "markdown",
"id": "applied-calculation",
"metadata": {},
"source": [
"## SOL_DECIMAL_DIVISOR decimal\n",
@ -75,16 +95,16 @@
{
"cell_type": "code",
"execution_count": null,
"id": "junior-yield",
"id": "starting-affair",
"metadata": {},
"outputs": [],
"source": [
"SOL_DECIMAL_DIVISOR = decimal.Decimal(1000000000)"
"SOL_DECIMAL_DIVISOR = decimal.Decimal(10 ** SOL_DECIMALS)"
]
},
{
"cell_type": "markdown",
"id": "selective-honor",
"id": "oriental-measurement",
"metadata": {},
"source": [
"## NUM_TOKENS\n",
@ -95,7 +115,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "north-apparatus",
"id": "spectacular-professional",
"metadata": {},
"outputs": [],
"source": [
@ -104,7 +124,7 @@
},
{
"cell_type": "markdown",
"id": "reflected-riverside",
"id": "narrative-trustee",
"metadata": {},
"source": [
"## NUM_MARKETS\n",
@ -115,7 +135,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "helpful-delhi",
"id": "brutal-cherry",
"metadata": {},
"outputs": [],
"source": [
@ -124,7 +144,7 @@
},
{
"cell_type": "markdown",
"id": "parliamentary-water",
"id": "artistic-zoning",
"metadata": {},
"source": [
"# WARNING_DISCLAIMER_TEXT\n",
@ -135,7 +155,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "stable-coating",
"id": "greek-engagement",
"metadata": {},
"outputs": [],
"source": [
@ -155,7 +175,7 @@
},
{
"cell_type": "markdown",
"id": "healthy-marine",
"id": "closing-bennett",
"metadata": {},
"source": [
"## MangoConstants\n",
@ -166,7 +186,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "sensitive-cosmetic",
"id": "municipal-methodology",
"metadata": {},
"outputs": [],
"source": [
@ -176,7 +196,7 @@
},
{
"cell_type": "markdown",
"id": "incoming-parliament",
"id": "brown-composite",
"metadata": {},
"source": [
"# 🏃 Running\n",
@ -187,7 +207,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "broadband-norwegian",
"id": "expired-director",
"metadata": {},
"outputs": [],
"source": [

View File

@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
"id": "satellite-eleven",
"id": "early-accordance",
"metadata": {},
"source": [
"# ⚠ Warning\n",
@ -16,7 +16,7 @@
},
{
"cell_type": "markdown",
"id": "taken-sound",
"id": "composite-contest",
"metadata": {},
"source": [
"# 🥭 Liquidation\n",
@ -31,7 +31,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "shaped-plasma",
"id": "arctic-saver",
"metadata": {
"jupyter": {
"source_hidden": true
@ -43,13 +43,13 @@
"\n",
"from solana.publickey import PublicKey\n",
"\n",
"from BaseModel import Group, MarginAccount\n",
"from BaseModel import Group, MarginAccount, TokenValue\n",
"from AccountLiquidator import ForceCancelOrdersAccountLiquidator\n"
]
},
{
"cell_type": "markdown",
"id": "cosmetic-province",
"id": "advanced-proof",
"metadata": {},
"source": [
"## 🦺 Safety\n",
@ -63,7 +63,7 @@
},
{
"cell_type": "markdown",
"id": "analyzed-pollution",
"id": "atmospheric-hanging",
"metadata": {},
"source": [
"## 📇 Collateralisation Ratios Details\n",
@ -81,7 +81,7 @@
},
{
"cell_type": "markdown",
"id": "double-cross",
"id": "caroline-grain",
"metadata": {},
"source": [
"# 💧 Liquidation Process"
@ -89,7 +89,7 @@
},
{
"cell_type": "markdown",
"id": "indie-villa",
"id": "entitled-james",
"metadata": {},
"source": [
"## 📇 Steps\n",
@ -117,7 +117,7 @@
},
{
"cell_type": "markdown",
"id": "downtown-horse",
"id": "handled-harmony",
"metadata": {},
"source": [
"# 🏃 Running\n",
@ -134,7 +134,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "patent-lodging",
"id": "greater-schema",
"metadata": {},
"outputs": [],
"source": [
@ -144,7 +144,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "solved-summit",
"id": "logical-utilization",
"metadata": {},
"outputs": [],
"source": [
@ -161,10 +161,9 @@
" print(\"No default wallet file available.\")\n",
" else:\n",
" print(\"Wallet Balances Before:\")\n",
" print(f\" SOL balance: {default_context.fetch_sol_balance(default_wallet.address):>18,.8f}\")\n",
" group = Group.load(default_context)\n",
" for token in group.tokens:\n",
" print(f\"{token.name:>7} balance: {default_context.fetch_token_balance(default_wallet.address, token.mint):>18,.8f}\")\n",
" balances_before = group.fetch_balances(default_wallet.address)\n",
" TokenValue.report(print, balances_before)\n",
"\n",
" prices = group.fetch_token_prices()\n",
" margin_account = MarginAccount.load(default_context, PublicKey(MARGIN_ACCOUNT_TO_LIQUIDATE), group)\n",
@ -185,9 +184,12 @@
" intrinsic_balance_sheets_after = margin_account_after_liquidation.get_intrinsic_balance_sheets(group_after)\n",
" print(\"Margin Account After:\", intrinsic_balance_sheets_after)\n",
" print(\"Wallet Balances After:\")\n",
" print(f\" SOL balance: {default_context.fetch_sol_balance(default_wallet.address):>18,.8f}\")\n",
" for token in group.tokens:\n",
" print(f\"{token.name:>7} balance: {default_context.fetch_token_balance(default_wallet.address, token.mint):>18,.8f}\")\n"
" balances_after = group_after.fetch_balances(default_wallet.address)\n",
" TokenValue.report(print, balances_after)\n",
"\n",
" print(\"Wallet Balances Changes:\")\n",
" changes = TokenValue.changes(balances_before, balances_after)\n",
" TokenValue.report(print, changes)\n"
]
}
],

View File

@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
"id": "executed-lithuania",
"id": "restricted-genius",
"metadata": {},
"source": [
"# ⚠ Warning\n",
@ -16,7 +16,7 @@
},
{
"cell_type": "markdown",
"id": "latest-vacuum",
"id": "coordinate-identification",
"metadata": {},
"source": [
"# 🥭 SimpleLiquidator\n",
@ -27,7 +27,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "rising-graham",
"id": "fundamental-sleeve",
"metadata": {
"jupyter": {
"source_hidden": true
@ -47,7 +47,7 @@
},
{
"cell_type": "markdown",
"id": "disciplinary-plant",
"id": "treated-painting",
"metadata": {},
"source": [
"# SimpleLiquidator class\n",
@ -69,7 +69,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "adjacent-burton",
"id": "innovative-escape",
"metadata": {},
"outputs": [],
"source": [
@ -124,8 +124,10 @@
" return\n",
"\n",
" for mam in highest_first:\n",
" wallet_balances_before = _token_balances_from_wallet(self.context, self.wallet, group)\n",
" self.logger.info(f\"Wallet balances before:\\n{wallet_balances_before}\")\n",
" balances_before = group.fetch_balances(self.wallet.address)\n",
" self.logger.info(\"Wallet balances before:\")\n",
" TokenValue.report(self.logger.info, balances_before)\n",
"\n",
" self.logger.info(f\"Margin account balances before:\\n{mam.balances}\")\n",
" self.logger.info(f\"Liquidating margin account: {mam.margin_account}\\n{mam.balance_sheet}\")\n",
" transaction_id = self.account_liquidator.liquidate(group, mam.margin_account, prices)\n",
@ -140,14 +142,21 @@
" margin_account_after_liquidation = MarginAccount.load(self.context, mam.margin_account.address, group_after)\n",
" intrinsic_balances_after = margin_account_after_liquidation.get_intrinsic_balances(group_after)\n",
" self.logger.info(f\"Margin account balances after: {intrinsic_balances_after}\")\n",
" wallet_balances_after = _token_balances_from_wallet(self.context, self.wallet, group)\n",
" self.logger.info(f\"Wallet balances after:\\n{wallet_balances_after}\")\n",
"\n",
" self.logger.info(\"Wallet Balances After:\")\n",
" balances_after = group_after.fetch_balances(self.wallet.address)\n",
" TokenValue.report(self.logger.info, balances_after)\n",
"\n",
" self.logger.info(\"Wallet Balances Changes:\")\n",
" changes = TokenValue.changes(balances_before, balances_after)\n",
" TokenValue.report(self.logger.info, changes)\n",
"\n",
" self.wallet_balancer(prices)\n"
]
},
{
"cell_type": "markdown",
"id": "nutritional-virginia",
"id": "olive-revolution",
"metadata": {},
"source": [
"# 🏃 Running"
@ -156,7 +165,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "unable-means",
"id": "extended-uruguay",
"metadata": {},
"outputs": [],
"source": [