Trying to be clearer about liquidation balances.

This commit is contained in:
Geoff Taylor 2021-04-26 16:02:53 +01:00
parent 5079995361
commit add7f5648c
5 changed files with 187 additions and 142 deletions

View File

@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
"id": "going-hands",
"id": "responsible-sample",
"metadata": {},
"source": [
"# ⚠ Warning\n",
@ -16,7 +16,7 @@
},
{
"cell_type": "markdown",
"id": "rolled-jacob",
"id": "adequate-rotation",
"metadata": {},
"source": [
"# 🥭 Classes\n",
@ -33,7 +33,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "organized-batch",
"id": "silver-prospect",
"metadata": {
"jupyter": {
"source_hidden": true
@ -60,7 +60,7 @@
},
{
"cell_type": "markdown",
"id": "selective-pontiac",
"id": "developed-initial",
"metadata": {},
"source": [
"## Version enum\n",
@ -71,7 +71,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "greatest-young",
"id": "clean-recorder",
"metadata": {},
"outputs": [],
"source": [
@ -86,7 +86,7 @@
},
{
"cell_type": "markdown",
"id": "floral-progress",
"id": "noticed-immunology",
"metadata": {},
"source": [
"## SerumAccountFlags class\n",
@ -97,7 +97,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "resistant-japan",
"id": "damaged-sport",
"metadata": {},
"outputs": [],
"source": [
@ -139,7 +139,7 @@
},
{
"cell_type": "markdown",
"id": "accredited-livestock",
"id": "massive-choice",
"metadata": {},
"source": [
"## MangoAccountFlags class\n",
@ -150,7 +150,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "dirty-ghost",
"id": "leading-external",
"metadata": {},
"outputs": [],
"source": [
@ -183,7 +183,7 @@
},
{
"cell_type": "markdown",
"id": "decimal-schedule",
"id": "talented-therapy",
"metadata": {},
"source": [
"## Index class"
@ -192,7 +192,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "municipal-concord",
"id": "french-sunrise",
"metadata": {},
"outputs": [],
"source": [
@ -218,7 +218,7 @@
},
{
"cell_type": "markdown",
"id": "dependent-diameter",
"id": "fewer-eating",
"metadata": {},
"source": [
"## AggregatorConfig class"
@ -227,7 +227,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "statutory-fraud",
"id": "jewish-specification",
"metadata": {},
"outputs": [],
"source": [
@ -259,7 +259,7 @@
},
{
"cell_type": "markdown",
"id": "descending-commitment",
"id": "formal-language",
"metadata": {},
"source": [
"## Round class"
@ -268,7 +268,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "monthly-standing",
"id": "endangered-directive",
"metadata": {},
"outputs": [],
"source": [
@ -292,7 +292,7 @@
},
{
"cell_type": "markdown",
"id": "fleet-principal",
"id": "potential-reader",
"metadata": {},
"source": [
"## Answer class"
@ -301,7 +301,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "dense-fever",
"id": "naked-worker",
"metadata": {},
"outputs": [],
"source": [
@ -326,7 +326,7 @@
},
{
"cell_type": "markdown",
"id": "right-raleigh",
"id": "residential-scientist",
"metadata": {},
"source": [
"## Aggregator class"
@ -335,7 +335,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "fluid-topic",
"id": "loaded-lecture",
"metadata": {},
"outputs": [],
"source": [
@ -401,7 +401,7 @@
},
{
"cell_type": "markdown",
"id": "checked-funeral",
"id": "later-belarus",
"metadata": {},
"source": [
"## BasketTokenMetadata class\n"
@ -410,7 +410,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "suburban-basics",
"id": "greatest-causing",
"metadata": {},
"outputs": [],
"source": [
@ -438,7 +438,7 @@
},
{
"cell_type": "markdown",
"id": "ongoing-termination",
"id": "intensive-regulation",
"metadata": {},
"source": [
"## MarketMetadata class"
@ -447,7 +447,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "appointed-wheel",
"id": "short-malawi",
"metadata": {},
"outputs": [],
"source": [
@ -482,7 +482,7 @@
},
{
"cell_type": "markdown",
"id": "medieval-weapon",
"id": "golden-intermediate",
"metadata": {},
"source": [
"## Group class"
@ -491,7 +491,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "mathematical-campbell",
"id": "adaptive-protection",
"metadata": {},
"outputs": [],
"source": [
@ -609,7 +609,7 @@
},
{
"cell_type": "markdown",
"id": "resident-cannon",
"id": "neither-infrastructure",
"metadata": {},
"source": [
"## TokenAccount class"
@ -618,7 +618,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "choice-walter",
"id": "headed-sacrifice",
"metadata": {},
"outputs": [],
"source": [
@ -650,7 +650,7 @@
},
{
"cell_type": "markdown",
"id": "equivalent-lexington",
"id": "alleged-firmware",
"metadata": {},
"source": [
"## OpenOrders class\n"
@ -659,7 +659,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "distinguished-jason",
"id": "sapphire-qualification",
"metadata": {},
"outputs": [],
"source": [
@ -759,7 +759,7 @@
},
{
"cell_type": "markdown",
"id": "manual-finger",
"id": "primary-netherlands",
"metadata": {},
"source": [
"## BalanceSheet class"
@ -768,12 +768,13 @@
{
"cell_type": "code",
"execution_count": null,
"id": "developed-corner",
"id": "stunning-carnival",
"metadata": {},
"outputs": [],
"source": [
"class BalanceSheet:\n",
" def __init__(self, liabilities: Decimal, settled_assets: Decimal, unsettled_assets: Decimal):\n",
" def __init__(self, token: typing.Optional[BasketTokenMetadata], liabilities: Decimal, settled_assets: Decimal, unsettled_assets: Decimal):\n",
" self.token: typing.Optional[BasketTokenMetadata] = token\n",
" self.liabilities: Decimal = liabilities\n",
" self.settled_assets: Decimal = settled_assets\n",
" self.unsettled_assets: Decimal = unsettled_assets\n",
@ -793,7 +794,11 @@
" return self.assets / self.liabilities\n",
"\n",
" def __str__(self) -> str:\n",
" return f\"\"\"« BalanceSheet:\n",
" name = \"«Unspecified»\"\n",
" if self.token is not None:\n",
" name = self.token.name\n",
"\n",
" return f\"\"\"« BalanceSheet [{name}]:\n",
" Assets : {self.assets:>18,.8f}\n",
" Settled Assets : {self.settled_assets:>18,.8f}\n",
" Unsettled Assets : {self.unsettled_assets:>18,.8f}\n",
@ -809,7 +814,7 @@
},
{
"cell_type": "markdown",
"id": "floppy-injection",
"id": "asian-donor",
"metadata": {},
"source": [
"## MarginAccount class\n"
@ -818,7 +823,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "enclosed-plain",
"id": "missing-eight",
"metadata": {},
"outputs": [],
"source": [
@ -939,7 +944,8 @@
"\n",
" balance_sheets: typing.List[typing.Optional[BalanceSheet]] = [None] * NUM_TOKENS\n",
" for index in range(NUM_TOKENS):\n",
" balance_sheets[index] = BalanceSheet(liabilities[index], settled_assets[index], unsettled_assets[index])\n",
" balance_sheets[index] = BalanceSheet(group.tokens[index], liabilities[index],\n",
" settled_assets[index], unsettled_assets[index])\n",
"\n",
" return balance_sheets\n",
"\n",
@ -953,6 +959,7 @@
" unsettled_assets = balance_sheet.unsettled_assets * prices[index]\n",
" token_metadata = group.tokens[index]\n",
" priced[index] = BalanceSheet(\n",
" token_metadata,\n",
" token_metadata.round(liabilities),\n",
" token_metadata.round(settled_assets),\n",
" token_metadata.round(unsettled_assets)\n",
@ -972,7 +979,7 @@
" settled_assets += balance_sheet.settled_assets\n",
" unsettled_assets += balance_sheet.unsettled_assets\n",
"\n",
" return BalanceSheet(liabilities, settled_assets, unsettled_assets)\n",
" return BalanceSheet(None, liabilities, settled_assets, unsettled_assets)\n",
"\n",
" def __str__(self) -> str:\n",
" deposits = \", \".join([f\"{item:,.8f}\" for item in self.deposits])\n",
@ -998,7 +1005,7 @@
},
{
"cell_type": "markdown",
"id": "standard-clothing",
"id": "attended-backing",
"metadata": {},
"source": [
"# 🏃 Running"
@ -1007,7 +1014,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "criminal-church",
"id": "altered-danger",
"metadata": {},
"outputs": [],
"source": [

View File

@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
"id": "undefined-batch",
"id": "characteristic-evidence",
"metadata": {},
"source": [
"# ⚠ Warning\n",
@ -16,7 +16,7 @@
},
{
"cell_type": "markdown",
"id": "processed-prison",
"id": "regulated-forward",
"metadata": {},
"source": [
"# 🥭 Context\n",
@ -26,7 +26,7 @@
},
{
"cell_type": "markdown",
"id": "unable-daisy",
"id": "medium-gravity",
"metadata": {},
"source": [
"## Environment Variables\n",
@ -41,7 +41,7 @@
},
{
"cell_type": "markdown",
"id": "silver-burns",
"id": "continuous-service",
"metadata": {},
"source": [
"## Provided Configured Objects\n",
@ -61,7 +61,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "bearing-posting",
"id": "under-millennium",
"metadata": {
"jupyter": {
"source_hidden": true
@ -85,7 +85,7 @@
},
{
"cell_type": "markdown",
"id": "immune-republic",
"id": "naval-killing",
"metadata": {},
"source": [
"## AccountInfo class\n",
@ -96,7 +96,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "double-diesel",
"id": "pleased-plaza",
"metadata": {},
"outputs": [],
"source": [
@ -139,7 +139,7 @@
},
{
"cell_type": "markdown",
"id": "realistic-jersey",
"id": "separate-capacity",
"metadata": {},
"source": [
"## Context class"
@ -148,7 +148,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "classical-cosmetic",
"id": "blessed-biography",
"metadata": {},
"outputs": [],
"source": [
@ -253,6 +253,15 @@
" def lookup_token_name(self, token_address: PublicKey) -> str:\n",
" return Context._lookup_name_by_address(token_address, MangoConstants[self.cluster][\"symbols\"]) or \"« Unknown Token »\"\n",
"\n",
" def wait_for_confirmation(self, transaction_id: str, max_wait_in_seconds: int = 60) -> None:\n",
" for wait in range(0, max_wait_in_seconds):\n",
" time.sleep(1)\n",
" confirmed = default_context.client.get_confirmed_transaction(transaction_id)\n",
" if confirmed[\"result\"] is not None:\n",
" print(f\"Confirmed after {wait} seconds.\")\n",
" return\n",
" print(f\"Timed out after {wait} seconds waiting on transaction {transaction_id}.\")\n",
"\n",
" def __str__(self) -> str:\n",
" return f\"\"\"« Context:\n",
" Cluster: {self.cluster}\n",
@ -269,7 +278,7 @@
},
{
"cell_type": "markdown",
"id": "distant-impact",
"id": "rising-anthony",
"metadata": {},
"source": [
"## default_context object\n",
@ -280,7 +289,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "south-adaptation",
"id": "victorian-gossip",
"metadata": {},
"outputs": [],
"source": [
@ -299,7 +308,7 @@
},
{
"cell_type": "markdown",
"id": "liberal-harvey",
"id": "precious-twins",
"metadata": {},
"source": [
"## solana_context object\n",
@ -310,7 +319,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "mechanical-pitch",
"id": "dramatic-indication",
"metadata": {},
"outputs": [],
"source": [
@ -322,7 +331,7 @@
},
{
"cell_type": "markdown",
"id": "protecting-forward",
"id": "radical-avenue",
"metadata": {},
"source": [
"## serum_context object\n",
@ -333,7 +342,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "standard-velvet",
"id": "infinite-giant",
"metadata": {},
"outputs": [],
"source": [
@ -345,7 +354,7 @@
},
{
"cell_type": "markdown",
"id": "moral-appearance",
"id": "alone-stanford",
"metadata": {},
"source": [
"# 🏃 Running\n",
@ -356,7 +365,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "governmental-township",
"id": "noticed-aquarium",
"metadata": {},
"outputs": [],
"source": [

View File

@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
"id": "blind-liverpool",
"id": "joint-pride",
"metadata": {},
"source": [
"# ⚠ Warning\n",
@ -16,7 +16,7 @@
},
{
"cell_type": "markdown",
"id": "enclosed-greenhouse",
"id": "optical-effects",
"metadata": {},
"source": [
"# 🥭 Instructions\n",
@ -27,7 +27,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "incorporate-seventh",
"id": "buried-colombia",
"metadata": {},
"outputs": [],
"source": [
@ -42,7 +42,7 @@
"from solana.sysvar import SYSVAR_CLOCK_PUBKEY\n",
"from spl.token.constants import TOKEN_PROGRAM_ID\n",
"\n",
"from Classes import BasketTokenMetadata, Group, MarginAccount, MarketMetadata, TokenAccount\n",
"from Classes import BalanceSheet, BasketTokenMetadata, Group, MarginAccount, MarketMetadata, TokenAccount\n",
"from Context import AccountInfo, Context\n",
"from Layouts import FORCE_CANCEL, PARTIAL_LIQUIDATE\n",
"from Wallet import Wallet\n"
@ -50,7 +50,7 @@
},
{
"cell_type": "markdown",
"id": "guided-gauge",
"id": "mobile-enforcement",
"metadata": {},
"source": [
"# InstructionBuilder class\n",
@ -61,7 +61,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "reliable-wesley",
"id": "interstate-thirty",
"metadata": {},
"outputs": [],
"source": [
@ -79,7 +79,7 @@
},
{
"cell_type": "markdown",
"id": "sound-synthetic",
"id": "according-oriental",
"metadata": {},
"source": [
"# ForceCancelOrdersInstructionBuilder class"
@ -87,7 +87,7 @@
},
{
"cell_type": "markdown",
"id": "entitled-diary",
"id": "dying-camping",
"metadata": {},
"source": [
"## Rust Interface\n",
@ -119,7 +119,7 @@
},
{
"cell_type": "markdown",
"id": "alert-baghdad",
"id": "golden-falls",
"metadata": {},
"source": [
"## Client API call\n",
@ -163,7 +163,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "potential-apollo",
"id": "listed-armor",
"metadata": {},
"outputs": [],
"source": [
@ -263,7 +263,7 @@
},
{
"cell_type": "markdown",
"id": "standing-polish",
"id": "charged-plaintiff",
"metadata": {},
"source": [
"# LiquidateInstructionBuilder class\n",
@ -275,7 +275,7 @@
},
{
"cell_type": "markdown",
"id": "occupational-tsunami",
"id": "looking-western",
"metadata": {},
"source": [
"## Rust Interface\n",
@ -321,7 +321,7 @@
},
{
"cell_type": "markdown",
"id": "written-helmet",
"id": "invisible-theater",
"metadata": {},
"source": [
"## Client API call\n",
@ -358,7 +358,7 @@
},
{
"cell_type": "markdown",
"id": "stable-rendering",
"id": "incoming-proceeding",
"metadata": {},
"source": [
"## from_margin_account_and_market() function\n",
@ -379,7 +379,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "controlled-flash",
"id": "applied-exception",
"metadata": {},
"outputs": [],
"source": [
@ -417,23 +417,39 @@
" )\n",
"\n",
" @staticmethod\n",
" def from_margin_account_and_market(context: Context, group: Group, wallet: Wallet, margin_account: MarginAccount, prices: typing.List[Decimal]) -> \"LiquidateInstructionBuilder\":\n",
" def from_margin_account_and_market(context: Context, group: Group, wallet: Wallet, margin_account: MarginAccount, prices: typing.List[Decimal]) -> typing.Optional[\"LiquidateInstructionBuilder\"]:\n",
" oracles = list([mkt.oracle for mkt in group.markets])\n",
"\n",
" balance_sheets = margin_account.get_priced_balance_sheets(group, prices)\n",
" print(\"Priced balance sheets\", balance_sheets)\n",
"\n",
" margin_account_with_most_liabilities_token_index = min(range(len(balance_sheets)), key=lambda i: balance_sheets[i].value)\n",
" margin_account_with_most_assets_token_index = max(range(len(balance_sheets)), key=lambda i: balance_sheets[i].value)\n",
" sorted_by_assets = sorted(balance_sheets, key=lambda sheet: sheet.assets)\n",
" sorted_by_liabilities = sorted(balance_sheets, key=lambda sheet: sheet.liabilities)\n",
"\n",
" input_token = group.tokens[margin_account_with_most_liabilities_token_index]\n",
" output_token = group.tokens[margin_account_with_most_assets_token_index]\n",
" most_assets = sorted_by_assets[0]\n",
" most_liabilities = sorted_by_liabilities[0]\n",
" if most_assets.token == most_liabilities:\n",
" # If there's a weirdness where the account with the biggest assets is also the one\n",
" # with the biggest liabilities, pick the next-best one by assets.\n",
" most_assets = sorted_by_assets[1]\n",
"\n",
" wallet_input_token_account = wallet.fetch_largest_token_account(context, input_token.mint)\n",
" wallet_output_token_account = wallet.fetch_largest_token_account(context, output_token.mint)\n",
" if most_assets.value == Decimal(0):\n",
" print(f\"Margin account {margin_account.address} has no assets to take.\")\n",
" return None\n",
"\n",
" if most_liabilities.value == Decimal(0):\n",
" print(f\"Margin account {margin_account.address} has no liabilities to fund.\")\n",
" return None\n",
"\n",
" wallet_input_token_account = wallet.fetch_largest_token_account(context, most_liabilities.token.mint)\n",
" wallet_output_token_account = wallet.fetch_largest_token_account(context, most_assets.token.mint)\n",
" wallet_input_token_data = TokenAccount.parse(wallet_input_token_account.data)\n",
"\n",
" return LiquidateInstructionBuilder(context, group, wallet, margin_account, oracles, input_token, output_token, wallet_input_token_account, wallet_output_token_account, wallet_input_token_data.amount)\n",
"\n",
" return LiquidateInstructionBuilder(context, group, wallet, margin_account, oracles,\n",
" most_liabilities.token, most_assets.token,\n",
" wallet_input_token_account,\n",
" wallet_output_token_account,\n",
" wallet_input_token_data.amount)\n",
"\n",
" def __str__(self) -> str:\n",
" # Print the members out using the Rust parameter order and names.\n",
@ -455,7 +471,7 @@
},
{
"cell_type": "markdown",
"id": "international-dressing",
"id": "baking-genealogy",
"metadata": {},
"source": [
"# 🏃 Running"
@ -464,7 +480,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "outdoor-integrity",
"id": "ultimate-zimbabwe",
"metadata": {},
"outputs": [],
"source": [

View File

@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
"id": "configured-bishop",
"id": "thirty-prediction",
"metadata": {},
"source": [
"# ⚠ Warning\n",
@ -16,7 +16,7 @@
},
{
"cell_type": "markdown",
"id": "latin-ordinary",
"id": "minute-regulation",
"metadata": {},
"source": [
"# 🥭 Liquidation\n",
@ -33,7 +33,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "moral-directive",
"id": "necessary-spoke",
"metadata": {},
"outputs": [],
"source": [
@ -51,7 +51,7 @@
},
{
"cell_type": "markdown",
"id": "powerful-annotation",
"id": "forbidden-token",
"metadata": {},
"source": [
"## Collateralisation Ratios\n",
@ -69,7 +69,7 @@
},
{
"cell_type": "markdown",
"id": "divided-procedure",
"id": "relevant-burst",
"metadata": {},
"source": [
"## Safety\n",
@ -83,7 +83,7 @@
},
{
"cell_type": "markdown",
"id": "helpful-decline",
"id": "liked-browser",
"metadata": {},
"source": [
"# 💧 Liquidation Process"
@ -91,7 +91,7 @@
},
{
"cell_type": "markdown",
"id": "second-division",
"id": "impaired-mirror",
"metadata": {},
"source": [
"## Steps\n",
@ -119,7 +119,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "blind-robert",
"id": "technological-stake",
"metadata": {},
"outputs": [],
"source": [
@ -129,7 +129,7 @@
" self.wallet = wallet\n",
" self.group = group\n",
"\n",
" def liquidate(self, margin_account: MarginAccount) -> str:\n",
" def liquidate(self, margin_account: MarginAccount) -> typing.Optional[str]:\n",
" force_cancel_orders_instructions: typing.List[InstructionBuilder] = []\n",
" for index, market_metadata in enumerate(self.group.markets):\n",
" open_orders = margin_account.open_orders_accounts[index]\n",
@ -144,6 +144,9 @@
" [transaction.add(builder.build()) for builder in force_cancel_orders_instructions]\n",
"\n",
" liquidate_instruction = LiquidateInstructionBuilder.from_margin_account_and_market(default_context, group, wallet, margin_account, prices)\n",
" if liquidate_instruction is None:\n",
" return None\n",
"\n",
" transaction.add(liquidate_instruction.build())\n",
"\n",
" for instruction in transaction.instructions:\n",
@ -161,7 +164,7 @@
},
{
"cell_type": "markdown",
"id": "appointed-depression",
"id": "supreme-specialist",
"metadata": {},
"source": [
"# 🏃 Running"
@ -170,7 +173,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "progressive-fountain",
"id": "governmental-february",
"metadata": {},
"outputs": [],
"source": [
@ -180,7 +183,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "proud-premium",
"id": "environmental-calgary",
"metadata": {},
"outputs": [],
"source": [
@ -198,7 +201,7 @@
" else:\n",
" wallet = Wallet.load(filename)\n",
" group = Group.load(default_context)\n",
" print(\"Before Balances:\")\n",
" print(\"Wallet Balances Before:\")\n",
" print(f\" SOL balance: {default_context.fetch_sol_balance(wallet.address):>18,.8f}\")\n",
" group = Group.load(default_context)\n",
" for token in group.tokens:\n",
@ -206,26 +209,23 @@
"\n",
" prices = group.get_prices()\n",
" margin_account = MarginAccount.load(default_context, group, PublicKey(MARGIN_ACCOUNT_TO_LIQUIDATE))\n",
" print(\"Before\", margin_account.get_balance_sheet_totals(group, prices))\n",
" print(\"Margin Account Before:\", margin_account.get_native_balance_sheets(group))\n",
" liquidator = Liquidator(default_context, wallet, group)\n",
" transaction_id = liquidator.liquidate(margin_account)\n",
" print(\"Transaction ID:\", transaction_id)\n",
" print(\"Waiting for confirmation...\")\n",
" if transaction_id is None:\n",
" print(\"No transaction sent.\")\n",
" else:\n",
" print(\"Transaction ID:\", transaction_id)\n",
" print(\"Waiting for confirmation...\")\n",
"\n",
" for wait in range(0, 60):\n",
" time.sleep(1)\n",
" confirmed = default_context.client.get_confirmed_transaction(transaction_id)\n",
" if confirmed[\"result\"] is not None:\n",
" print(f\"Confirmed after {wait} seconds.\")\n",
" break\n",
" context.wait_for_confirmation(transaction_id)\n",
"\n",
" margin_account_adfter_liquidation = MarginAccount.load(default_context, group, PublicKey(MARGIN_ACCOUNT_TO_LIQUIDATE))\n",
" print(\"After\", margin_account_adfter_liquidation.get_balance_sheet_totals(group, prices))\n",
" print(\"After Balances:\")\n",
" print(f\" SOL balance: {default_context.fetch_sol_balance(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(wallet.address, token.mint):>18,.8f}\")\n"
" margin_account_adfter_liquidation = MarginAccount.load(default_context, group, PublicKey(MARGIN_ACCOUNT_TO_LIQUIDATE))\n",
" print(\"Margin Account After:\", margin_account_adfter_liquidation.get_native_balance_sheets(group))\n",
" print(\"Wallet Balances After:\")\n",
" print(f\" SOL balance: {default_context.fetch_sol_balance(wallet.address):>18,.8f}\")\n",
" for token in group.tokens:\n",
" print(f\"{token.name:>7} balance: {default_context.fetch_token_balance(wallet.address, token.mint):>18,.8f}\")\n"
]
}
],

View File

@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
"id": "willing-yacht",
"id": "entitled-pickup",
"metadata": {},
"source": [
"# ⚠ Warning\n",
@ -16,7 +16,7 @@
},
{
"cell_type": "markdown",
"id": "instructional-universe",
"id": "recreational-acquisition",
"metadata": {},
"source": [
"# 🥭 Mango + Pandas 🐼🐼\n",
@ -31,12 +31,8 @@
{
"cell_type": "code",
"execution_count": null,
"id": "smaller-atlantic",
"metadata": {
"jupyter": {
"source_hidden": true
}
},
"id": "generic-chemical",
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
@ -49,7 +45,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "unavailable-tamil",
"id": "norwegian-interstate",
"metadata": {},
"outputs": [],
"source": [
@ -80,35 +76,52 @@
"print(\"Loading pandas dataframe...\")\n",
"data = []\n",
"df_index = []\n",
"sheet_formats = {}\n",
"for index, margin_account in enumerate(margin_accounts):\n",
" balance_sheet = margin_account.get_balance_sheet_totals(group, prices)\n",
" df_index += [str(margin_account.address)]\n",
" data += [{\"Collateral Ratio\": balance_sheet.collateral_ratio,\n",
" row = {\"Collateral Ratio\": balance_sheet.collateral_ratio,\n",
" \"Available Collateral\": balance_sheet.assets - balance_sheet.liabilities,\n",
" \"Liabilities\": balance_sheet.liabilities,\n",
" \"Assets\": balance_sheet.assets,\n",
" \"Settled Assets\": balance_sheet.settled_assets,\n",
" \"Unsettled Assets\": balance_sheet.unsettled_assets,\n",
" \"Owner\": margin_account.owner\n",
" }]\n",
" }\n",
" native_balance_sheets = margin_account.get_native_balance_sheets(group)\n",
" priced_balance_sheets = margin_account.get_priced_balance_sheets(group, prices)\n",
" for index, sheet in enumerate(native_balance_sheets):\n",
" row[f\"{sheet.token.name} Liabilities (Native)\"] = sheet.liabilities\n",
" row[f\"{sheet.token.name} Assets (Native)\"] = sheet.assets\n",
" sheet_formats[f\"{sheet.token.name} Liabilities (Native)\"] = \"{:,.8f}\"\n",
" sheet_formats[f\"{sheet.token.name} Assets (Native)\"] = \"{:,.8f}\"\n",
" priced_sheet = priced_balance_sheets[index]\n",
" row[f\"{priced_sheet.token.name} Liabilities (Priced)\"] = priced_sheet.liabilities\n",
" row[f\"{priced_sheet.token.name} Assets (Priced)\"] = priced_sheet.assets\n",
" sheet_formats[f\"{sheet.token.name} Liabilities (Priced)\"] = \"${:,.2f}\"\n",
" sheet_formats[f\"{sheet.token.name} Assets (Priced)\"] = \"${:,.2f}\"\n",
" data += [row]\n",
"\n",
"df = pd.DataFrame(data, index=df_index)\n",
"\n",
"print(f\"Done. Time taken: {time.time() - start_time}\")\n",
"\n",
"def render_styled(df: pd.DataFrame):\n",
" return df.style.format({\n",
" \"Collateral Ratio\": \"{:,.2%}\",\n",
" \"Available Collateral\": \"${:,.2f}\",\n",
" \"Liabilities\": \"${:,.2f}\",\n",
" \"Assets\": \"${:,.2f}\",\n",
" \"Settled Assets\": \"${:,.2f}\",\n",
" \"Unsettled Assets\": \"${:,.2f}\",\n",
"})\n"
" all_formats = {\n",
" \"Collateral Ratio\": \"{:,.2%}\",\n",
" \"Available Collateral\": \"${:,.2f}\",\n",
" \"Liabilities\": \"${:,.2f}\",\n",
" \"Assets\": \"${:,.2f}\",\n",
" \"Settled Assets\": \"${:,.2f}\",\n",
" \"Unsettled Assets\": \"${:,.2f}\"\n",
" }\n",
" all_formats.update(sheet_formats)\n",
" return df.style.format(all_formats)\n"
]
},
{
"cell_type": "markdown",
"id": "going-norwegian",
"id": "japanese-relation",
"metadata": {},
"source": [
"# 🔥 Total Assets + Liabilities"
@ -117,7 +130,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "intellectual-savannah",
"id": "generic-sunday",
"metadata": {},
"outputs": [],
"source": [
@ -132,7 +145,7 @@
},
{
"cell_type": "markdown",
"id": "thirty-tattoo",
"id": "diagnostic-commander",
"metadata": {},
"source": [
"# 🔝 Top 10 Greatest Assets\n",
@ -143,7 +156,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "noticed-liability",
"id": "durable-magnet",
"metadata": {},
"outputs": [],
"source": [
@ -152,7 +165,7 @@
},
{
"cell_type": "markdown",
"id": "interpreted-reverse",
"id": "respective-responsibility",
"metadata": {},
"source": [
"# 🔝 Top 10 Greatest Liabilities\n",
@ -163,7 +176,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "impressive-component",
"id": "naked-harassment",
"metadata": {},
"outputs": [],
"source": [
@ -172,7 +185,7 @@
},
{
"cell_type": "markdown",
"id": "novel-disney",
"id": "tamil-tennis",
"metadata": {},
"source": [
"# 🔝 Top 10 Least Collateralised\n",
@ -185,7 +198,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "cardiovascular-squad",
"id": "rural-force",
"metadata": {},
"outputs": [],
"source": [
@ -195,7 +208,7 @@
},
{
"cell_type": "markdown",
"id": "artificial-carolina",
"id": "infinite-duncan",
"metadata": {},
"source": [
"# 💧 Liquidatable\n",
@ -208,7 +221,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "suitable-education",
"id": "overall-minneapolis",
"metadata": {},
"outputs": [],
"source": [
@ -221,7 +234,7 @@
},
{
"cell_type": "markdown",
"id": "acceptable-tunnel",
"id": "recovered-weapon",
"metadata": {},
"source": [
"# 🥭 Ripe Mangoes\n",
@ -234,7 +247,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "senior-notion",
"id": "deluxe-elevation",
"metadata": {},
"outputs": [],
"source": [