<jupyter_start><jupyter_text>⚠ WarningTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gl/OpinionatedGeek%2Fmango-explorer/HEAD?filepath=Pandas.ipynb) _🏃‍♀️ To run this notebook press the ⏩ icon in the toolbar above._[🥭 Mango Markets](https://mango.markets/) support is available at: [Docs](https://docs.mango.markets/) | [Discord](https://discord.gg/67jySBhxrg) | [Twitter](https://twitter.com/mangomarkets) | [Github](https://github.com/blockworks-foundation) | [Email](mailto:<EMAIL>)  🥭 Mango + Pandas 🐼🐼This notebook loads margin account data into a Pandas `DataFrame`.The `DataFrame` is then queried for the total assets and liabilities, the Top 10 margin accounts with the most assets and the most liabilities, and then the Top 10 margin accounts closest to liquidation.The data remains in the `DataFrame` called `df` so you can easily add your own queries and analyses.<jupyter_code>import logging
import mango
import pandas as pd
import time

start_time = time.time()
context = mango.Context.default()

print("Loading group...")
group = mango.Group.load(context)
print(f"Done. Time taken: {time.time() - start_time}")

print("Loading prices...")
prices = group.fetch_token_prices(context)
print(f"Done. Time taken: {time.time() - start_time}")

print("Loading margin accounts...")
margin_accounts = mango.MarginAccount.load_all_for_group_with_open_orders(context, context.program_id, group)
print(f"Done. {len(margin_accounts)} accounts. Time taken: {time.time() - start_time}")

print("Loading pandas dataframe...")
data = []
df_index = []
sheet_formats = {}
for index, margin_account in enumerate(margin_accounts):
    balance_sheet = margin_account.get_balance_sheet_totals(group, prices)
    df_index += [str(margin_account.address)]
    row = {
        "Collateral Ratio": balance_sheet.collateral_ratio,
        "Available Collateral": balance_sheet.assets - balance_sheet.liabilities,
        "Liabilities": balance_sheet.liabilities,
        "Assets": balance_sheet.assets,
        "Settled Assets": balance_sheet.settled_assets,
        "Unsettled Assets": balance_sheet.unsettled_assets,
        "Owner": margin_account.owner
    }
    intrinsic_balance_sheets = margin_account.get_intrinsic_balance_sheets(group)
    priced_balance_sheets = margin_account.get_priced_balance_sheets(group, prices)
    for index, sheet in enumerate(intrinsic_balance_sheets):
        if sheet is None:
            continue
        row[f"{sheet.token.name} Liabilities (Intrinsic)"] = sheet.liabilities
        row[f"{sheet.token.name} Assets (Intrinsic)"] = sheet.assets
        sheet_formats[f"{sheet.token.name} Liabilities (Intrinsic)"] = "{:,.8f}"
        sheet_formats[f"{sheet.token.name} Assets (Intrinsic)"] = "{:,.8f}"
        priced_sheet = priced_balance_sheets[index]
        row[f"{priced_sheet.token.name} Liabilities (Priced)"] = priced_sheet.liabilities
        row[f"{priced_sheet.token.name} Assets (Priced)"] = priced_sheet.assets
        sheet_formats[f"{sheet.token.name} Liabilities (Priced)"] = "${:,.2f}"
        sheet_formats[f"{sheet.token.name} Assets (Priced)"] = "${:,.2f}"
    data += [row]


df = pd.DataFrame(data, index=df_index)

print(f"Done. Time taken: {time.time() - start_time}")

def render_styled(df: pd.DataFrame):
    all_formats = {
        "Collateral Ratio": "{:,.2%}",
        "Available Collateral": "${:,.2f}",
        "Liabilities": "${:,.2f}",
        "Assets": "${:,.2f}",
        "Settled Assets": "${:,.2f}",
        "Unsettled Assets": "${:,.2f}"
    }
    all_formats.update(sheet_formats)
    return df.style.format(all_formats)<jupyter_output><empty_output><jupyter_text>🔥 Total Assets + Liabilities<jupyter_code>print(f"""
Total Assets:      ${df['Assets'].sum():>15,.2f}
Total Liabilities: ${df['Liabilities'].sum():>15,.2f}
Empty Accounts:     {len(df[df["Collateral Ratio"] == 0]):>15,}
Liquidatable:       {len(df[(df["Collateral Ratio"] != 0) & (df["Collateral Ratio"] <= 1.1)]):>15,}
🥭 Ripe Mangoes:    {len(df[(df["Collateral Ratio"] > 1.1) & (df["Collateral Ratio"] < 1.2)]):>15,}
""")<jupyter_output><empty_output><jupyter_text>🔝 Top 10 Greatest AssetsThe top 10 margin accounts with most assets<jupyter_code>render_styled(df.sort_values("Assets", ascending=False).head(10))<jupyter_output><empty_output><jupyter_text>🔝 Top 10 Greatest LiabilitiesThe top 10 margin accounts with most liabilities<jupyter_code>render_styled(df.sort_values("Liabilities", ascending=False).head(10))<jupyter_output><empty_output><jupyter_text>🔝 Top 10 Least CollateralisedThe top 10 least collateralised margin accountsCollect all margin accounts that have a non-zero Collateral Ratio (so have some liabilities). Then sort them from least-collateralised to most-collateralised.<jupyter_code>nonzero = df[df["Collateral Ratio"] != 0]
render_styled(nonzero.sort_values("Collateral Ratio", ascending=True).head(10))<jupyter_output><empty_output><jupyter_text>💧 LiquidatableAn account is 'liquidatable' when its available collateral falls below the group's maintenance collataeral threshold.This code shows all liquidatable margin accounts, sorted by the available collateral (_not_ the collateral ratio).<jupyter_code>simplified = nonzero.drop(["Settled Assets", "Unsettled Assets"], axis=1)
liquidatable = simplified[simplified["Collateral Ratio"] < group.maint_coll_ratio].copy()

print(f"There are {len(liquidatable)} liquidatable accounts.")
render_styled(liquidatable.sort_values("Available Collateral", ascending=False).head(len(liquidatable)))<jupyter_output><empty_output><jupyter_text>🥭 Ripe Mangoes'Ripe mangoes' are margin accounts that are below the group's initial margin requirements but have not yet fallen below the liquidation threshold.This code shows all ripe mangoes, sorted by the available collateral (_not_ the collateral ratio).<jupyter_code>ripe = simplified[simplified["Collateral Ratio"] < group.init_coll_ratio]
only_ripe = ripe[ripe["Collateral Ratio"] >= group.maint_coll_ratio].copy()

print(f"There are {len(only_ripe)} 🥭 ripe mangoes.")
render_styled(only_ripe.sort_values("Available Collateral", ascending=False).head(len(only_ripe)))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13093980992608237, 'fraction_numerical': 0.008749434303816564, 'mean_word_length': 5.570862239841428, 'pattern_counts': {'":': 13, '<': 34, '<?xml version=': 0, '>': 37, 'https://': 7, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '46963', 'license': 'MIT', 'n_tokens_mistral': 2235, 'n_tokens_neox': 2096, 'n_words': 518, 'path': 'Pandas.ipynb', 'repo_name': 'mschneider/mango-explorer', 'size': '6649'}