{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "from datetime import datetime\n", "from tqdm import tqdm\n", "\n", "import time\n", "import requests\n", "import datetime\n", "import pandas as pd\n", "from collections import defaultdict\n", "from typing import Any, Union\n", "from string import Template\n", "from enum import Enum\n", "from tqdm import tqdm\n", "import numpy as np\n", "from pathlib import Path" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "tools = pd.read_parquet('/Users/arshath/play/openautonomy/olas-prediction-live-dashboard/data/tools.parquet')\n", "tools['trader_address'] = tools['trader_address'].str.lower()\n", "fpmmTrades = pd.read_parquet('/Users/arshath/play/openautonomy/olas-prediction-live-dashboard/data/fpmmTrades.parquet')\n", "# trades = pd.read_parquet('/Users/arshath/play/openautonomy/olas-prediction-live-dashboard/data/all_trades_profitability.parquet')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "IRRELEVANT_TOOLS = [\n", " \"openai-text-davinci-002\",\n", " \"openai-text-davinci-003\",\n", " \"openai-gpt-3.5-turbo\",\n", " \"openai-gpt-4\",\n", " \"stabilityai-stable-diffusion-v1-5\",\n", " \"stabilityai-stable-diffusion-xl-beta-v2-2-2\",\n", " \"stabilityai-stable-diffusion-512-v2-1\",\n", " \"stabilityai-stable-diffusion-768-v2-1\",\n", " \"deepmind-optimization-strong\",\n", " \"deepmind-optimization\",\n", "]\n", "QUERY_BATCH_SIZE = 1000\n", "DUST_THRESHOLD = 10000000000000\n", "INVALID_ANSWER_HEX = (\n", " \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"\n", ")\n", "INVALID_ANSWER = -1\n", "FPMM_CREATOR = \"0x89c5cc945dd550bcffb72fe42bff002429f46fec\"\n", "DEFAULT_FROM_DATE = \"1970-01-01T00:00:00\"\n", "DEFAULT_TO_DATE = \"2038-01-19T03:14:07\"\n", "DEFAULT_FROM_TIMESTAMP = 0\n", "DEFAULT_TO_TIMESTAMP = 2147483647\n", "WXDAI_CONTRACT_ADDRESS = \"0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d\"\n", "DEFAULT_MECH_FEE = 0.01\n", "DUST_THRESHOLD = 10000000000000\n", "SCRIPTS_DIR = Path('/Users/arshath/play/openautonomy/olas-prediction-live-dashboard/scripts')\n", "ROOT_DIR = SCRIPTS_DIR.parent\n", "DATA_DIR = ROOT_DIR / \"data\"\n", "\n", "class MarketState(Enum):\n", " \"\"\"Market state\"\"\"\n", "\n", " OPEN = 1\n", " PENDING = 2\n", " FINALIZING = 3\n", " ARBITRATING = 4\n", " CLOSED = 5\n", "\n", " def __str__(self) -> str:\n", " \"\"\"Prints the market status.\"\"\"\n", " return self.name.capitalize()\n", "\n", "\n", "class MarketAttribute(Enum):\n", " \"\"\"Attribute\"\"\"\n", "\n", " NUM_TRADES = \"Num_trades\"\n", " WINNER_TRADES = \"Winner_trades\"\n", " NUM_REDEEMED = \"Num_redeemed\"\n", " INVESTMENT = \"Investment\"\n", " FEES = \"Fees\"\n", " MECH_CALLS = \"Mech_calls\"\n", " MECH_FEES = \"Mech_fees\"\n", " EARNINGS = \"Earnings\"\n", " NET_EARNINGS = \"Net_earnings\"\n", " REDEMPTIONS = \"Redemptions\"\n", " ROI = \"ROI\"\n", "\n", " def __str__(self) -> str:\n", " \"\"\"Prints the attribute.\"\"\"\n", " return self.value\n", "\n", " def __repr__(self) -> str:\n", " \"\"\"Prints the attribute representation.\"\"\"\n", " return self.name\n", "\n", " @staticmethod\n", " def argparse(s: str) -> \"MarketAttribute\":\n", " \"\"\"Performs string conversion to MarketAttribute.\"\"\"\n", " try:\n", " return MarketAttribute[s.upper()]\n", " except KeyError as e:\n", " raise ValueError(f\"Invalid MarketAttribute: {s}\") from e\n", "\n", "\n", "ALL_TRADES_STATS_DF_COLS = [\n", " \"trader_address\",\n", " \"trade_id\",\n", " \"creation_timestamp\",\n", " \"title\",\n", " \"market_status\",\n", " \"collateral_amount\",\n", " \"outcome_index\",\n", " \"trade_fee_amount\",\n", " \"outcomes_tokens_traded\",\n", " \"current_answer\",\n", " \"is_invalid\",\n", " \"winning_trade\",\n", " \"earnings\",\n", " \"redeemed\",\n", " \"redeemed_amount\",\n", " \"num_mech_calls\",\n", " \"mech_fee_amount\",\n", " \"net_earnings\",\n", " \"roi\",\n", "]\n", "\n", "SUMMARY_STATS_DF_COLS = [\n", " \"trader_address\",\n", " \"num_trades\",\n", " \"num_winning_trades\",\n", " \"num_redeemed\",\n", " \"total_investment\",\n", " \"total_trade_fees\",\n", " \"num_mech_calls\",\n", " \"total_mech_fees\",\n", " \"total_earnings\",\n", " \"total_redeemed_amount\",\n", " \"total_net_earnings\",\n", " \"total_net_earnings_wo_mech_fees\",\n", " \"total_roi\",\n", " \"total_roi_wo_mech_fees\",\n", " \"mean_mech_calls_per_trade\",\n", " \"mean_mech_fee_amount_per_trade\",\n", "]\n", "headers = {\n", " \"Accept\": \"application/json, multipart/mixed\",\n", " \"Content-Type\": \"application/json\",\n", "}\n", "\n", "\n", "omen_xdai_trades_query = Template(\n", " \"\"\"\n", " {\n", " fpmmTrades(\n", " where: {\n", " type: Buy,\n", " fpmm_: {\n", " creator: \"${fpmm_creator}\"\n", " creationTimestamp_gte: \"${fpmm_creationTimestamp_gte}\",\n", " creationTimestamp_lt: \"${fpmm_creationTimestamp_lte}\"\n", " },\n", " creationTimestamp_gte: \"${creationTimestamp_gte}\",\n", " creationTimestamp_lte: \"${creationTimestamp_lte}\"\n", " id_gt: \"${id_gt}\"\n", " }\n", " first: ${first}\n", " orderBy: id\n", " orderDirection: asc\n", " ) {\n", " id\n", " title\n", " collateralToken\n", " outcomeTokenMarginalPrice\n", " oldOutcomeTokenMarginalPrice\n", " type\n", " creator {\n", " id\n", " }\n", " creationTimestamp\n", " collateralAmount\n", " collateralAmountUSD\n", " feeAmount\n", " outcomeIndex\n", " outcomeTokensTraded\n", " transactionHash\n", " fpmm {\n", " id\n", " outcomes\n", " title\n", " answerFinalizedTimestamp\n", " currentAnswer\n", " isPendingArbitration\n", " arbitrationOccurred\n", " openingTimestamp\n", " condition {\n", " id\n", " }\n", " }\n", " }\n", " }\n", " \"\"\"\n", ")\n", "\n", "\n", "conditional_tokens_gc_user_query = Template(\n", " \"\"\"\n", " {\n", " user(id: \"${id}\") {\n", " userPositions(\n", " first: ${first}\n", " where: {\n", " id_gt: \"${userPositions_id_gt}\"\n", " }\n", " orderBy: id\n", " ) {\n", " balance\n", " id\n", " position {\n", " id\n", " conditionIds\n", " }\n", " totalBalance\n", " wrappedBalance\n", " }\n", " }\n", " }\n", " \"\"\"\n", ")\n", "\n", "\n", "def _to_content(q: str) -> dict[str, Any]:\n", " \"\"\"Convert the given query string to payload content, i.e., add it under a `queries` key and convert it to bytes.\"\"\"\n", " finalized_query = {\n", " \"query\": q,\n", " \"variables\": None,\n", " \"extensions\": {\"headers\": None},\n", " }\n", " return finalized_query\n", "\n", "\n", "def _query_omen_xdai_subgraph(\n", " from_timestamp: float,\n", " to_timestamp: float,\n", " fpmm_from_timestamp: float,\n", " fpmm_to_timestamp: float,\n", ") -> dict[str, Any]:\n", " \"\"\"Query the subgraph.\"\"\"\n", " url = \"https://api.thegraph.com/subgraphs/name/protofire/omen-xdai\"\n", "\n", " grouped_results = defaultdict(list)\n", " id_gt = \"\"\n", "\n", " while True:\n", " query = omen_xdai_trades_query.substitute(\n", " fpmm_creator=FPMM_CREATOR.lower(),\n", " creationTimestamp_gte=int(from_timestamp),\n", " creationTimestamp_lte=int(to_timestamp),\n", " fpmm_creationTimestamp_gte=int(fpmm_from_timestamp),\n", " fpmm_creationTimestamp_lte=int(fpmm_to_timestamp),\n", " first=QUERY_BATCH_SIZE,\n", " id_gt=id_gt,\n", " )\n", " content_json = _to_content(query)\n", " res = requests.post(url, headers=headers, json=content_json)\n", " result_json = res.json()\n", " user_trades = result_json.get(\"data\", {}).get(\"fpmmTrades\", [])\n", "\n", " if not user_trades:\n", " break\n", "\n", " for trade in user_trades:\n", " fpmm_id = trade.get(\"fpmm\", {}).get(\"id\")\n", " grouped_results[fpmm_id].append(trade)\n", "\n", " id_gt = user_trades[len(user_trades) - 1][\"id\"]\n", "\n", " all_results = {\n", " \"data\": {\n", " \"fpmmTrades\": [\n", " trade\n", " for trades_list in grouped_results.values()\n", " for trade in trades_list\n", " ]\n", " }\n", " }\n", "\n", " return all_results\n", "\n", "\n", "def _query_conditional_tokens_gc_subgraph(creator: str) -> dict[str, Any]:\n", " \"\"\"Query the subgraph.\"\"\"\n", " url = \"https://api.thegraph.com/subgraphs/name/gnosis/conditional-tokens-gc\"\n", "\n", " all_results: dict[str, Any] = {\"data\": {\"user\": {\"userPositions\": []}}}\n", " userPositions_id_gt = \"\"\n", " while True:\n", " query = conditional_tokens_gc_user_query.substitute(\n", " id=creator.lower(),\n", " first=QUERY_BATCH_SIZE,\n", " userPositions_id_gt=userPositions_id_gt,\n", " )\n", " content_json = {\"query\": query}\n", " res = requests.post(url, headers=headers, json=content_json)\n", " result_json = res.json()\n", " user_data = result_json.get(\"data\", {}).get(\"user\", {})\n", "\n", " if not user_data:\n", " break\n", "\n", " user_positions = user_data.get(\"userPositions\", [])\n", "\n", " if user_positions:\n", " all_results[\"data\"][\"user\"][\"userPositions\"].extend(user_positions)\n", " userPositions_id_gt = user_positions[len(user_positions) - 1][\"id\"]\n", " else:\n", " break\n", "\n", " if len(all_results[\"data\"][\"user\"][\"userPositions\"]) == 0:\n", " return {\"data\": {\"user\": None}}\n", "\n", " return all_results\n", "\n", "\n", "def convert_hex_to_int(x: Union[str, float]) -> Union[int, float]:\n", " \"\"\"Convert hex to int\"\"\"\n", " if isinstance(x, float):\n", " return np.nan\n", " elif isinstance(x, str):\n", " if x == INVALID_ANSWER_HEX:\n", " return -1\n", " else:\n", " return int(x, 16)\n", "\n", "\n", "def wei_to_unit(wei: int) -> float:\n", " \"\"\"Converts wei to currency unit.\"\"\"\n", " return wei / 10**18\n", "\n", "\n", "def _is_redeemed(user_json: dict[str, Any], fpmmTrade: dict[str, Any]) -> bool:\n", " \"\"\"Returns whether the user has redeemed the position.\"\"\"\n", " user_positions = user_json[\"data\"][\"user\"][\"userPositions\"]\n", " outcomes_tokens_traded = int(fpmmTrade[\"outcomeTokensTraded\"])\n", " condition_id = fpmmTrade[\"fpmm.condition.id\"]\n", "\n", " for position in user_positions:\n", " position_condition_ids = position[\"position\"][\"conditionIds\"]\n", " balance = int(position[\"balance\"])\n", "\n", " if condition_id in position_condition_ids:\n", " if balance == 0:\n", " return True\n", " # return early\n", " return False\n", " return False\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def determine_market_status(trade, current_answer):\n", " \"\"\"Determine the market status of a trade.\"\"\"\n", " if current_answer is np.nan and time.time() >= int(trade[\"fpmm.openingTimestamp\"]):\n", " return MarketState.PENDING\n", " elif current_answer == np.nan:\n", " return MarketState.OPEN\n", " elif trade[\"fpmm.isPendingArbitration\"]:\n", " return MarketState.ARBITRATING\n", " elif time.time() < int(trade[\"fpmm.answerFinalizedTimestamp\"]):\n", " return MarketState.FINALIZING\n", " return MarketState.CLOSED" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "all_traders = []\n", "\n", "for trader_address in tqdm(\n", " fpmmTrades[\"trader_address\"].unique(),\n", " total=len(fpmmTrades[\"trader_address\"].unique()),\n", " desc=\"Analysing creators\"\n", "):\n", " trades = fpmmTrades[fpmmTrades[\"trader_address\"] == trader_address]\n", " tools_usage = tools[tools[\"trader_address\"].str.lower() == trader_address]\n", "\n", " # Prepare the DataFrame\n", " trades_df = pd.DataFrame(columns=ALL_TRADES_STATS_DF_COLS)\n", "\n", " if trades.empty:\n", " continue\n", "\n", " # Fetch user's conditional tokens gc graph\n", " try:\n", " user_json = _query_conditional_tokens_gc_subgraph(trader_address)\n", " except Exception as e:\n", " print(f\"Error fetching user data: {e}\")\n", " raise e\n", " \n", " break" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i, trade in tqdm(trades.iterrows(), total=len(trades), desc=\"Analysing trades\"):\n", " if not trade['fpmm.currentAnswer']:\n", " print(f\"Skipping trade {i} because currentAnswer is NaN\")\n", " continue\n", "\n", " creation_timestamp_utc = datetime.datetime.fromtimestamp(\n", " int(trade[\"creationTimestamp\"]), tz=datetime.timezone.utc\n", " )\n", " collateral_amount = wei_to_unit(float(trade[\"collateralAmount\"]))\n", " fee_amount = wei_to_unit(float(trade[\"feeAmount\"]))\n", " outcome_tokens_traded = wei_to_unit(float(trade[\"outcomeTokensTraded\"]))\n", " earnings, winner_trade = (0, False)\n", " redemption = _is_redeemed(user_json, trade)\n", " current_answer = trade[\"fpmm.currentAnswer\"]\n", " # Determine market status\n", " market_status = determine_market_status(trade, current_answer)\n", "\n", " # Skip non-closed markets\n", " if market_status != MarketState.CLOSED:\n", " print(\n", " f\"Skipping trade {i} because market is not closed. Market Status: {market_status}\"\n", " )\n", " continue\n", " current_answer = convert_hex_to_int(current_answer)\n", "\n", " # Compute invalidity\n", " is_invalid = current_answer == INVALID_ANSWER\n", "\n", " # Compute earnings and winner trade status\n", " if is_invalid:\n", " earnings = collateral_amount\n", " winner_trade = False\n", " elif int(trade[\"outcomeIndex\"]) == current_answer:\n", " earnings = outcome_tokens_traded\n", " winner_trade = True\n", "\n", " # Compute mech calls\n", " num_mech_calls = (\n", " tools_usage[\"prompt_request\"].apply(lambda x: trade[\"title\"] in x).sum()\n", " )\n", " net_earnings = (\n", " earnings\n", " - fee_amount\n", " - (num_mech_calls * DEFAULT_MECH_FEE)\n", " - collateral_amount\n", " )\n", "\n", " break" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# all_traders = []\n", "# for trader_address in tqdm(\n", "# fpmmTrades[\"trader_address\"].unique(),\n", "# total=len(fpmmTrades[\"trader_address\"].unique()),\n", "# desc=\"Analysing creators\",\n", "# ):\n", "\n", "# trades = fpmmTrades[fpmmTrades[\"trader_address\"] == trader_address]\n", "# tools_usage = tools[tools[\"trader_address\"] == trader_address]\n", "\n", "# # Prepare the DataFrame\n", "# trades_df = pd.DataFrame(columns=ALL_TRADES_STATS_DF_COLS)\n", "# if trades.empty:\n", "# continue\n", "\n", "# # Fetch user's conditional tokens gc graph\n", "# try:\n", "# user_json = _query_conditional_tokens_gc_subgraph(trader_address)\n", "# except Exception as e:\n", "# print(f\"Error fetching user data: {e}\")\n", "# raise e\n", "\n", "# # Iterate over the trades\n", "# for i, trade in tqdm(trades.iterrows(), total=len(trades), desc=\"Analysing trades\"):\n", "# try:\n", "# if not trade['fpmm.currentAnswer']:\n", "# print(f\"Skipping trade {i} because currentAnswer is NaN\")\n", "# continue\n", "# # Parsing and computing shared values\n", "# creation_timestamp_utc = datetime.datetime.fromtimestamp(\n", "# int(trade[\"creationTimestamp\"]), tz=datetime.timezone.utc\n", "# )\n", "# collateral_amount = wei_to_unit(float(trade[\"collateralAmount\"]))\n", "# fee_amount = wei_to_unit(float(trade[\"feeAmount\"]))\n", "# outcome_tokens_traded = wei_to_unit(float(trade[\"outcomeTokensTraded\"]))\n", "# earnings, winner_trade = (0, False)\n", "# redemption = _is_redeemed(user_json, trade)\n", "# current_answer = trade[\"fpmm.currentAnswer\"]\n", "# # Determine market status\n", "# market_status = determine_market_status(trade, current_answer)\n", "\n", "# # Skip non-closed markets\n", "# if market_status != MarketState.CLOSED:\n", "# print(\n", "# f\"Skipping trade {i} because market is not closed. Market Status: {market_status}\"\n", "# )\n", "# continue\n", "# current_answer = convert_hex_to_int(current_answer)\n", "\n", "# # Compute invalidity\n", "# is_invalid = current_answer == INVALID_ANSWER\n", "\n", "# # Compute earnings and winner trade status\n", "# if is_invalid:\n", "# earnings = collateral_amount\n", "# winner_trade = False\n", "# elif trade[\"outcomeIndex\"] == current_answer:\n", "# earnings = outcome_tokens_traded\n", "# winner_trade = True\n", "\n", "# # Compute mech calls\n", "# num_mech_calls = (\n", "# tools_usage[\"prompt_request\"].apply(lambda x: trade[\"title\"] in x).sum()\n", "# )\n", "# net_earnings = (\n", "# earnings\n", "# - fee_amount\n", "# - (num_mech_calls * DEFAULT_MECH_FEE)\n", "# - collateral_amount\n", "# )\n", "\n", "# # Assign values to DataFrame\n", "# trades_df.loc[i] = {\n", "# \"trader_address\": trader_address,\n", "# \"trade_id\": trade[\"id\"],\n", "# \"market_status\": market_status.name,\n", "# \"creation_timestamp\": creation_timestamp_utc,\n", "# \"title\": trade[\"title\"],\n", "# \"collateral_amount\": collateral_amount,\n", "# \"outcome_index\": trade[\"outcomeIndex\"],\n", "# \"trade_fee_amount\": fee_amount,\n", "# \"outcomes_tokens_traded\": outcome_tokens_traded,\n", "# \"current_answer\": current_answer,\n", "# \"is_invalid\": is_invalid,\n", "# \"winning_trade\": winner_trade,\n", "# \"earnings\": earnings,\n", "# \"redeemed\": redemption,\n", "# \"redeemed_amount\": earnings if redemption else 0,\n", "# \"num_mech_calls\": num_mech_calls,\n", "# \"mech_fee_amount\": num_mech_calls * DEFAULT_MECH_FEE,\n", "# \"net_earnings\": net_earnings,\n", "# \"roi\": net_earnings / (collateral_amount + fee_amount + num_mech_calls * DEFAULT_MECH_FEE),\n", "# }\n", "# except Exception as e:\n", "# print(f\"Error processing trade {i}: {e}\")\n", "# raise e" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import pandas as pd" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "trades = pd.read_parquet('/Users/arshath/play/openautonomy/olas-prediction-live-dashboard/data/all_trades_profitability.parquet')\n", "tools = pd.read_parquet('/Users/arshath/play/openautonomy/olas-prediction-live-dashboard/data/tools.parquet')" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Index(['trader_address', 'trade_id', 'creation_timestamp', 'title',\n", " 'market_status', 'collateral_amount', 'outcome_index',\n", " 'trade_fee_amount', 'outcomes_tokens_traded', 'current_answer',\n", " 'is_invalid', 'winning_trade', 'earnings', 'redeemed',\n", " 'redeemed_amount', 'num_mech_calls', 'mech_fee_amount', 'net_earnings',\n", " 'roi'],\n", " dtype='object')" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "trades.columns" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "trades = pd.read_parquet('/Users/arshath/play/openautonomy/olas-prediction-live-dashboard/data/all_trades_profitability.parquet')\n", "trades['creation_timestamp'] = pd.to_datetime(trades['creation_timestamp'], unit='s')\n", "trades = trades[trades['creation_timestamp'].dt.year == 2024]\n", "trades_winning = trades.groupby(['title','winning_trade']).size().unstack().fillna(0)\n", "trades_winning_perc = trades_winning[True] / (trades_winning[True] + trades_winning[False])\n", "trades_winning_perc = trades_winning_perc.reset_index()\n", "trades_winning_perc.columns = ['title', 'winning_trade_perc']\n", "def bucket_winning_trade_perc(x):\n", " if x < 0.1:\n", " return 0.1\n", " elif x < 0.2:\n", " return 0.2\n", " elif x < 0.3:\n", " return 0.3\n", " elif x < 0.4:\n", " return 0.4\n", " elif x < 0.5:\n", " return 0.5\n", " elif x < 0.6:\n", " return 0.6\n", " elif x < 0.7:\n", " return 0.7\n", " elif x < 0.8:\n", " return 0.8\n", " elif x < 0.9:\n", " return 0.9\n", " else:\n", " return 1\n", "\n", "trades_winning_perc['winning_trade_perc_bucket'] = trades_winning_perc['winning_trade_perc'].apply(bucket_winning_trade_perc)\n", "trades_winning_perc['winning_trade_perc_bucket'].plot(kind='hist', bins=10)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "\n" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "akash", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.14" } }, "nbformat": 4, "nbformat_minor": 2 }