From 27edce0085d848d040148e72e11ec0ae1418525f Mon Sep 17 00:00:00 2001 From: DiTus Date: Mon, 22 Dec 2025 22:12:57 +0100 Subject: [PATCH] feat: add untracked aerodrome tools and todo analysis documents --- aerodrome/tools/create_agent.py | 70 +++++++++++++ aerodrome/tools/kpi_tracker.py | 134 +++++++++++++++++++++++++ todo/ANALYSIS_TEMPLATE.md | 70 +++++++++++++ todo/ATR_over_week.PNG | Bin 0 -> 56471 bytes todo/DYNAMIC_TIMEOUT_ANALYSIS.md | 43 ++++++++ todo/EXTENDED_SHADOW_TIMEOUT.md | 44 ++++++++ todo/KPI_IMPLEMENTATION_PLAN.md | 57 +++++++++++ todo/MAKER_VS_TAKER_ANALYSIS.md | 79 +++++++++++++++ todo/SHADOW_ORDER_ANALYSIS.md | 68 +++++++++++++ todo/data_needed_for_optymalization.md | 118 ++++++++++++++++++++++ todo/template._for_analisismd | 70 +++++++++++++ 11 files changed, 753 insertions(+) create mode 100644 aerodrome/tools/create_agent.py create mode 100644 aerodrome/tools/kpi_tracker.py create mode 100644 todo/ANALYSIS_TEMPLATE.md create mode 100644 todo/ATR_over_week.PNG create mode 100644 todo/DYNAMIC_TIMEOUT_ANALYSIS.md create mode 100644 todo/EXTENDED_SHADOW_TIMEOUT.md create mode 100644 todo/KPI_IMPLEMENTATION_PLAN.md create mode 100644 todo/MAKER_VS_TAKER_ANALYSIS.md create mode 100644 todo/SHADOW_ORDER_ANALYSIS.md create mode 100644 todo/data_needed_for_optymalization.md create mode 100644 todo/template._for_analisismd diff --git a/aerodrome/tools/create_agent.py b/aerodrome/tools/create_agent.py new file mode 100644 index 0000000..dcc4e9d --- /dev/null +++ b/aerodrome/tools/create_agent.py @@ -0,0 +1,70 @@ +import os +from eth_account import Account +from hyperliquid.exchange import Exchange +from hyperliquid.utils import constants +from dotenv import load_dotenv +from datetime import datetime, timedelta +import json + +# Load environment variables from a .env file if it exists +load_dotenv() + +def create_and_authorize_agent(): + """ + Creates and authorizes a new agent key pair using your main wallet, + following the correct SDK pattern. + """ + # --- STEP 1: Load your main wallet --- + # This is the wallet that holds the funds and has been activated on Hyperliquid. + main_wallet_private_key = os.environ.get("MAIN_WALLET_PRIVATE_KEY") + if not main_wallet_private_key: + main_wallet_private_key = input("Please enter the private key of your MAIN trading wallet: ") + + try: + main_account = Account.from_key(main_wallet_private_key) + print(f"\nāœ… Loaded main wallet: {main_account.address}") + except Exception as e: + print(f"āŒ Error: Invalid main wallet private key provided. Details: {e}") + return + + # --- STEP 2: Initialize the Exchange with your MAIN account --- + # This object is used to send the authorization transaction. + exchange = Exchange(main_account, constants.MAINNET_API_URL, account_address=main_account.address) + + # --- STEP 3: Create and approve the agent with a specific name --- + # agent name must be between 1 and 16 characters long + agent_name = "my_new_agent" + + print(f"\nšŸ”— Authorizing a new agent named '{agent_name}'...") + try: + # --- FIX: Pass only the agent name string to the function --- + approve_result, agent_private_key = exchange.approve_agent(agent_name) + + if approve_result.get("status") == "ok": + # Derive the agent's public address from the key we received + agent_account = Account.from_key(agent_private_key) + + print("\nšŸŽ‰ SUCCESS! Agent has been authorized on-chain.") + print("="*50) + print("SAVE THESE SECURELY. This is what your bot will use.") + print(f" Name: {agent_name}") + print(f" (Agent has a default long-term validity)") + print(f"šŸ”‘ Agent Private Key: {agent_private_key}") + print(f"šŸ  Agent Address: {agent_account.address}") + print("="*50) + print("\nYou can now set this private key as the AGENT_PRIVATE_KEY environment variable.") + else: + print("\nāŒ ERROR: Agent authorization failed.") + print(" Response:", approve_result) + if "Vault may not perform this action" in str(approve_result): + print("\n ACTION REQUIRED: This error means your main wallet (vault) has not been activated. " + "Please go to the Hyperliquid website, connect this wallet, and make a deposit to activate it.") + + + except Exception as e: + print(f"\nAn unexpected error occurred during authorization: {e}") + + +if __name__ == "__main__": + create_and_authorize_agent() + diff --git a/aerodrome/tools/kpi_tracker.py b/aerodrome/tools/kpi_tracker.py new file mode 100644 index 0000000..dda3f3e --- /dev/null +++ b/aerodrome/tools/kpi_tracker.py @@ -0,0 +1,134 @@ +import os +import csv +import time +import logging +from decimal import Decimal +from typing import Dict, Optional + +# Setup Logger +logger = logging.getLogger("KPI_TRACKER") +logger.setLevel(logging.INFO) +# Basic handler if not already handled by parent +if not logger.handlers: + ch = logging.StreamHandler() + formatter = logging.Formatter('%(asctime)s - KPI - %(message)s') + ch.setFormatter(formatter) + logger.addHandler(ch) + +KPI_FILE = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'logs', 'kpi_history.csv') + +def initialize_kpi_csv(): + """Creates the CSV with headers if it doesn't exist.""" + if not os.path.exists(os.path.dirname(KPI_FILE)): + os.makedirs(os.path.dirname(KPI_FILE)) + + if not os.path.exists(KPI_FILE): + with open(KPI_FILE, 'w', newline='') as f: + writer = csv.writer(f) + writer.writerow([ + "Timestamp", + "Date", + "NAV_Total_USD", + "Benchmark_HODL_USD", + "Alpha_USD", + "Uniswap_Val_USD", + "Uniswap_Fees_Claimed_USD", + "Uniswap_Fees_Unclaimed_USD", + "Hedge_Equity_USD", + "Hedge_PnL_Realized_USD", + "Hedge_Fees_Paid_USD", + "ETH_Price", + "Fee_Coverage_Ratio" + ]) + +def calculate_hodl_benchmark(initial_eth: Decimal, initial_usdc: Decimal, initial_hedge_usdc: Decimal, current_eth_price: Decimal) -> Decimal: + """Calculates value if assets were just held (Wallet Assets + Hedge Account Cash).""" + return (initial_eth * current_eth_price) + initial_usdc + initial_hedge_usdc + +def log_kpi_snapshot( + snapshot_data: Dict[str, float] +): + """ + Logs a KPI snapshot to CSV. + Expected keys in snapshot_data: + - initial_eth, initial_usdc, initial_hedge_usdc + - current_eth_price + - uniswap_pos_value_usd + - uniswap_fees_claimed_usd + - uniswap_fees_unclaimed_usd + - hedge_equity_usd + - hedge_pnl_realized_usd + - hedge_fees_paid_usd + - wallet_eth_bal, wallet_usdc_bal (Optional, for full NAV) + """ + try: + initialize_kpi_csv() + + # Convert all inputs to Decimal for precision + price = Decimal(str(snapshot_data.get('current_eth_price', 0))) + + # 1. Benchmark (HODL) + init_eth = Decimal(str(snapshot_data.get('initial_eth', 0))) + init_usdc = Decimal(str(snapshot_data.get('initial_usdc', 0))) + init_hedge = Decimal(str(snapshot_data.get('initial_hedge_usdc', 0))) + benchmark_val = calculate_hodl_benchmark(init_eth, init_usdc, init_hedge, price) + + # 2. Strategy NAV (Net Asset Value) + # NAV = Uni Pos + Uni Fees (Claimed+Unclaimed) + Hedge Equity + (Wallet Surplus - Initial Wallet Surplus?) + # For simplicity, we focus on the Strategy PnL components: + # Strategy Val = (Current Uni Pos) + (Claimed Fees) + (Unclaimed Fees) + (Hedge PnL Realized) + (Hedge Unrealized?) + # Note: Hedge Equity usually includes margin. We strictly want "Value Generated". + + uni_val = Decimal(str(snapshot_data.get('uniswap_pos_value_usd', 0))) + uni_fees_claimed = Decimal(str(snapshot_data.get('uniswap_fees_claimed_usd', 0))) + uni_fees_unclaimed = Decimal(str(snapshot_data.get('uniswap_fees_unclaimed_usd', 0))) + + # Hedge PnL (Realized + Unrealized) is better than Equity for PnL tracking, + # but Equity represents actual redeemable cash. Let's use Equity if provided, or PnL components. + hedge_equity = Decimal(str(snapshot_data.get('hedge_equity_usd', 0))) + hedge_fees = Decimal(str(snapshot_data.get('hedge_fees_paid_usd', 0))) + + # Simplified NAV for Strategy Comparison: + # We assume 'hedge_equity' is the Liquidation Value of the hedge account. + # But if we want strictly "Strategy Performance", we usually do: + # Current Value = Uni_Val + Unclaimed + Hedge_Equity + # (Assuming Hedge_Equity started at 0 or we track delta? No, usually Hedge Account has deposit). + + # Let's define NAV as Total Current Liquidation Value of Strategy Components + current_nav = uni_val + uni_fees_unclaimed + uni_fees_claimed + hedge_equity + + # Alpha + alpha = current_nav - benchmark_val + + # Coverage Ratio + total_hedge_cost = abs(hedge_fees) # + funding if available + total_uni_earnings = uni_fees_claimed + uni_fees_unclaimed + + if total_hedge_cost > 0: + coverage_ratio = total_uni_earnings / total_hedge_cost + else: + coverage_ratio = Decimal("999.0") # Infinite/Good + + # Write + with open(KPI_FILE, 'a', newline='') as f: + writer = csv.writer(f) + writer.writerow([ + int(time.time()), + time.strftime('%Y-%m-%d %H:%M:%S'), + f"{current_nav:.2f}", + f"{benchmark_val:.2f}", + f"{alpha:.2f}", + f"{uni_val:.2f}", + f"{uni_fees_claimed:.2f}", + f"{uni_fees_unclaimed:.2f}", + f"{hedge_equity:.2f}", + f"{snapshot_data.get('hedge_pnl_realized_usd', 0):.2f}", + f"{hedge_fees:.2f}", + f"{price:.2f}", + f"{coverage_ratio:.2f}" + ]) + + logger.info(f"šŸ“Š KPI Logged | NAV: ${current_nav:.2f} | Benchmark: ${benchmark_val:.2f} | Alpha: ${alpha:.2f}") + + except Exception as e: + logger.error(f"Failed to log KPI: {e}") diff --git a/todo/ANALYSIS_TEMPLATE.md b/todo/ANALYSIS_TEMPLATE.md new file mode 100644 index 0000000..8a0e931 --- /dev/null +++ b/todo/ANALYSIS_TEMPLATE.md @@ -0,0 +1,70 @@ +# Analysis Request: [Insert Topic Here] + +**Status:** [Draft / Pending Analysis / Completed] +**Date:** [YYYY-MM-DD] +**Priority:** [Low / Medium / High] + +--- + +## 1. User Description & Query +*(User: Fill this section with your design ideas, questions, code snippets, or links to files/web resources. Be as specific as possible about the goal.)* + +### Context +* **Goal:** +* **Current Behavior:** +* **Desired Behavior:** + +### References +* **Files:** `[filename.py]`, `[path/to/module]` +* **Links:** `[url]` + +### Specific Questions / Hypothesis +1. +2. + +--- + +*(The sections below are to be filled by the AI Agent upon request)* + +## 2. Agent Summary +*(AI: Summarize the user's request to ensure alignment on the objective.)* + +* **Objective:** +* **Key Constraints:** +* **Scope:** + +## 3. Main Analysis +*(AI: Perform the deep dive here. Use codebase knowledge, logic, and simulations.)* + +### 3.1 Codebase Investigation +* **Affected Components:** +* **Data Flow Analysis:** +* **Current Limitation/Bug:** + +### 3.2 Technical Options / Trade-offs +| Option | Pros | Cons | Complexity | +| :--- | :--- | :--- | :--- | +| **A. [Strategy A]** | ... | ... | ... | +| **B. [Strategy B]** | ... | ... | ... | + +### 3.3 Proposed Solution Design +* **Architecture:** +* **Logic Changes:** +* **Edge Cases Considered:** + +## 4. Risk Assessment +*(AI: What could go wrong? Performance, Security, or Stability impacts.)* + +* **Risk 1:** [Description] -> *Mitigation:* [Strategy] + +## 5. Conclusion +*(AI: Final verdict and recommendation.)* + +* **Recommendation:** + +## 6. Implementation Plan +*(AI: Step-by-step checklist to execute the recommendation.)* + +- [ ] Step 1: +- [ ] Step 2: +- [ ] Step 3: diff --git a/todo/ATR_over_week.PNG b/todo/ATR_over_week.PNG new file mode 100644 index 0000000000000000000000000000000000000000..6387b5fd7cacf8480068760fb0957101496dd480 GIT binary patch literal 56471 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∈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 LyHb4FIr9GiqR_h? literal 0 HcmV?d00001 diff --git a/todo/DYNAMIC_TIMEOUT_ANALYSIS.md b/todo/DYNAMIC_TIMEOUT_ANALYSIS.md new file mode 100644 index 0000000..2db4c38 --- /dev/null +++ b/todo/DYNAMIC_TIMEOUT_ANALYSIS.md @@ -0,0 +1,43 @@ +# Analysis Request: Dynamic Timeout for Shadow Orders + +**Status:** Completed +**Date:** 2025-12-20 +**Priority:** Medium + +--- + +## 1. User Description & Query +**Goal:** Optimize the Shadow Order simulation by making the "Time to Live" (timeout) dynamic based on market volatility. +**Logic:** +* **Low Volatility (Slow Market):** Orders sit on the book longer. Give the shadow order more time (e.g., 60s) to fill. +* **High Volatility (Fast Market):** Price moves quickly. If it doesn't fill instantly, it likely ran away. Timeout should be short (e.g., 10s) to fail fast. + +## 2. Agent Summary +* **Objective:** Implement a dynamic timeout calculation during shadow order creation. +* **Formula:** Inverse relationship with volatility. + +## 3. Main Analysis + +### 3.1 Volatility Scaling +We already calculate `vol_pct` (5-min rolling StdDev). +* **Base Vol:** `0.05%` (0.0005). +* **Base Timeout:** 30 seconds. + +**Formula:** +`timeout = Base_Timeout * (Base_Vol / Current_Vol)` + +**Examples:** +* **Low Vol (0.025%):** `30 * (0.05 / 0.025) = 60s` (Max cap). +* **Normal Vol (0.05%):** `30 * (0.05 / 0.05) = 30s`. +* **High Vol (0.15%):** `30 * (0.05 / 0.15) = 10s`. + +### 3.2 Constraints +* **Min Timeout:** 10s (Give at least some chance even in crazy markets). +* **Max Timeout:** 60s (Don't track stale orders forever). + +## 4. Conclusion +**Recommendation:** Implement this dynamic timeout alongside the shadow order logic. It makes the "Success/Fail" metric much more realistic for a Maker strategy in different regimes. + +## 5. Implementation Plan +- [ ] **Step 1:** Add `get_dynamic_timeout(vol_pct)` helper method. +- [ ] **Step 2:** Use this timeout when creating the shadow order entry. diff --git a/todo/EXTENDED_SHADOW_TIMEOUT.md b/todo/EXTENDED_SHADOW_TIMEOUT.md new file mode 100644 index 0000000..54db25a --- /dev/null +++ b/todo/EXTENDED_SHADOW_TIMEOUT.md @@ -0,0 +1,44 @@ +# Analysis Request: Extended Timeout for Shadow Orders + +**Status:** Completed +**Date:** 2025-12-20 +**Priority:** Medium + +--- + +## 1. User Description & Query +**Goal:** Extend the Shadow Order timeout to **10 minutes (600s)** to capture the "Mean Time to Execution" across different market conditions. +**Reasoning:** Instead of failing fast (which assumes Maker is bad if not instant), we want to gather data on *how long* it actually takes to fill. This helps optimize the timeout later. + +## 2. Agent Summary +* **Objective:** Modify `clp_hedger.py` to use a long fixed timeout (or much longer dynamic timeout) for shadow orders. +* **Risk:** "Success" at 9 minutes is effectively a "Failure" for hedging (Delta Drift). +* **Mitigation:** We are collecting *data*, not executing trades. A 9-minute fill log is valuable data point (it tells us "Maker is impossible here"). + +## 3. Main Analysis + +### 3.1 Data Value vs. Hedging Reality +* **Hedging Reality:** If a hedge takes > 30s to fill, the price has likely moved significantly. The "Hedge" is no longer hedging the original risk. +* **Data Value:** By waiting 10 minutes, we can generate a distribution curve: + * *50% fill in < 5s* (Great!) + * *30% fill in 5s-60s* (Okay for stable markets) + * *20% fill in > 60s* (Terrible) + * *If we used a 60s timeout, we would just see "20% Failed", losing the nuance.* + +### 3.2 Implementation Strategy +Instead of a complex dynamic timeout for now, let's set a **Fixed Long Timeout (600s)** for the Shadow Simulator. +* **Why?** We want to see the *actual* fill time for every order, not cut it off artificially. +* **Logging:** The log `filled in X.Xs` becomes the primary metric. + +### 3.3 Memory Impact +* Even with 1 trade per minute, 10 minutes = 10 items in the list. +* Memory usage is negligible (<1KB). + +## 4. Conclusion +**Recommendation:** Switch the Shadow Order logic to use a **Fixed 600s Timeout**. +* This turns the simulator into a "Fill Time Data Collector". +* We can analyze the logs later to find the "Optimal Timeout" (e.g., "95% of fills happen within 45s, so set timeout to 45s"). + +## 5. Implementation Plan +- [ ] **Step 1:** In `clp_hedger.py`, replace the dynamic timeout calculation with `timeout = 600`. +- [ ] **Step 2:** Update logging to ensure `fill_time` is prominent. diff --git a/todo/KPI_IMPLEMENTATION_PLAN.md b/todo/KPI_IMPLEMENTATION_PLAN.md new file mode 100644 index 0000000..633f117 --- /dev/null +++ b/todo/KPI_IMPLEMENTATION_PLAN.md @@ -0,0 +1,57 @@ +# KPI Implementation Proposal + +**Status:** Proposed +**Date:** 2025-12-20 + +## 1. Objective +Implement a robust KPI tracking system to answer: "Is this strategy actually making money compared to HODLing?" + +## 2. Architecture +We will introduce a lightweight **KPI Module** (`tools/kpi_tracker.py`) that is called periodically by `uniswap_manager.py`. + +### A. Data Sources +1. **Uniswap V3:** Current Position Value + Unclaimed Fees (from `uniswap_manager.py`). +2. **Hyperliquid:** Equity + Unrealized PnL (from `clp_hedger.py` / API). +3. **Wallet:** ETH/USDC balances (from Web3). +4. **History:** Initial Amounts (from `hedge_status.json`). + +### B. The Metrics (KPIs) + +#### 1. Net Asset Value (NAV) +* `NAV = (Uniswap Pos Value) + (Hyperliquid Equity) + (Wallet ETH * Price) + (Wallet USDC)` +* *Note:* Allows tracking total portfolio health. + +#### 2. Strategy vs. Benchmark (Alpha) +* **Strategy Value:** `Current NAV` +* **Benchmark Value (HODL):** + * Snapshot at start: `Initial ETH` + `Initial USDC`. + * Current Val: `(Initial ETH * Current Price) + Initial USDC`. +* **Alpha:** `Strategy Value - Benchmark Value`. + +#### 3. Fee Coverage Ratio +* `Ratio = (Uniswap Fees Earned) / (Hedge Cost)` +* *Hedge Cost:* Fees paid on Hyperliquid + Funding Paid. + +## 3. Implementation Plan + +### Step 1: Create `tools/kpi_tracker.py` +This module will handle the math and logging. +* **Functions:** + * `log_kpi_snapshot(nav_data, market_data)`: Appends to CSV. + * `calculate_benchmark(initial_snapshot, current_price)`: Returns HODL value. + +### Step 2: CSV Schema (`logs/kpi_history.csv`) +| Timestamp | NAV | Benchmark_NAV | Alpha | Uniswap_Fees_Acc | Hedge_Cost_Acc | Fee_Coverage | ETH_Price | +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +| ... | ... | ... | ... | ... | ... | ... | ... | + +### Step 3: Integration +* **Hook into `uniswap_manager.py`:** + * Every loop (or every hour), gather data. + * Call `kpi_tracker.log_kpi_snapshot()`. +* **Note:** `uniswap_manager.py` manages the slow loop, so it's the perfect place to record "macro" performance without adding latency to the hedger. + +## 4. Next Steps +1. Approve this plan? +2. I will generate `tools/kpi_tracker.py`. +3. I will integrate it into `uniswap_manager.py`. diff --git a/todo/MAKER_VS_TAKER_ANALYSIS.md b/todo/MAKER_VS_TAKER_ANALYSIS.md new file mode 100644 index 0000000..be7e157 --- /dev/null +++ b/todo/MAKER_VS_TAKER_ANALYSIS.md @@ -0,0 +1,79 @@ +# Analysis Request: Maker vs Taker for Hedging Optimization + +**Status:** Completed +**Date:** 2025-12-20 +**Priority:** Medium + +--- + +## 1. User Description & Query +**Goal:** Determine if using **Maker (Alo)** orders instead of **Taker (Ioc)** orders for "safe" rebalancing (in the middle of the range) would improve PnL. +**Hypothesis:** Maker orders earn rebates (or pay lower fees) and capture the spread, but risk non-execution (delta drift). Taker orders pay fees and cross the spread but guarantee immediate hedging. + +### Specific Questions +1. What data is needed to evaluate this trade-off? +2. How to measure the "Cost of Waiting" (Delta Drift)? + +--- + +## 2. Agent Summary +* **Objective:** Define the data requirements to backtest/simulate a "Maker Hedging Strategy." +* **Current State:** `clp_hedger.py` predominantly uses Taker orders (`Ioc`) for rebalancing to ensure the hedge matches the Uniswap delta instantly. Maker orders (`Alo`) are only used for passive closing. + +## 3. Main Analysis + +### 3.1 The Trade-off Equation +To know if Maker is better, we must solve: +$$ \text{Gain} > \text{Loss} $$ +$$ (\text{Spread Capture} + \text{Fee Rebate}) > (\text{Delta Drift Cost} + \text{Opportunity Cost}) $$ + +* **Spread Capture:** Selling at Ask vs. Selling at Bid. +* **Fee Rebate:** Hyperliquid pays rebates for Maker orders (e.g., 0.02%) vs charging Taker fees (e.g., 0.035%). Total swing ~0.055%. +* **Delta Drift:** While your Maker order sits on the book, the price moves. Your Uniswap LP delta changes, but your hedge delta doesn't. You are "under-hedged" or "over-hedged" for those seconds. + +### 3.2 Required Data for Simulation + +To simulate this, we cannot just look at OHLC candles. We need **Tick-Level Order Book Data**. + +#### A. Order Book Snapshots (The "Opportunity") +* **Metric:** **Bid-Ask Spread Width** over time. + * *Why:* If the spread is 0.01% (tight), Maker offers little gain. If it's 0.1% (wide), capturing it is huge. + * *Data:* `timestamp`, `best_bid`, `best_ask`. + +#### B. Trade Flow / Fill Probability (The "Risk") +* **Metric:** **Time to Fill (at Best Bid/Ask)**. + * *Why:* If you place a Maker buy at Best Bid, how long until someone sells into you? 1 second? 1 minute? + * *Data:* You need a recording of **all public trades** on Hyperliquid to match against your theoretical order price. + +#### C. Price Velocity (The "Drift") +* **Metric:** **Price Change per Second** during the "Wait Time". + * *Why:* If you wait 5 seconds for a fill, and ETH moves 0.2%, you just lost 0.2% in unhedged exposure to save 0.05% in fees. Bad trade. + +### 3.3 Implemented Solution: Shadow Order Simulator +The system now runs a real-time simulation engine to verify Maker feasibility without risking capital. + +#### Mechanism: +1. **Creation:** Every successful Taker trade (`Ioc`) triggers the creation of a "Shadow Order" at the passive price (Bid for Buy, Ask for Sell). +2. **Dynamic Timeout:** The "Time to Live" for the simulation is inversely proportional to volatility (`calculate_volatility()`): + * **Low Vol (Quiet):** Wait up to **60s**. + * **High Vol (Fast):** Timeout after **10s**. + * *Rationale:* In fast markets, if a fill isn't immediate, the price has likely moved too far, making a Maker strategy dangerous. +3. **Verification:** The main loop checks these shadow orders every tick against current `Ask` (for Buy) or `Bid` (for Sell) prices to confirm if a fill *definitely* would have occurred. + +#### Data Captured: +* `[SHADOW] SUCCESS`: Maker order would have filled (capturing spread + rebate). +* `[SHADOW] FAILED`: Price ran away (Taker was the correct choice to prevent delta drift). + +## 4. Risk Assessment +* **Risk:** **Adverse Selection.** Market makers (bots) are faster than you. They will only fill your order when the market is moving *against* you (e.g., you are buying, price is crashing). + * *Mitigation:* Analyze "Time to Success" logs. If successes only happen at the very end of the 60s window, the "Drift Cost" might exceed the "Spread Gain." + +## 5. Conclusion +**Recommendation:** +1. **Monitor Logs:** Let the simulator run for 48-72 hours across different market regimes (Weekend vs. Weekday). +2. **Decision Metric:** If Success Rate > 80% and Avg Fill Time < 15s, proceed to implement a "Passive First" hedging mode for the safe center of the CLP range. + +## 6. Implementation Plan +- [x] **Step 1:** Update `clp_hedger.py` to fetch and log `Bid` and `Ask` explicitly during execution. +- [x] **Step 2:** Implement `check_shadow_orders` and state management in `ScalperHedger`. +- [x] **Step 3:** Implement dynamic timeout logic based on rolling StdDev. diff --git a/todo/SHADOW_ORDER_ANALYSIS.md b/todo/SHADOW_ORDER_ANALYSIS.md new file mode 100644 index 0000000..ae0e974 --- /dev/null +++ b/todo/SHADOW_ORDER_ANALYSIS.md @@ -0,0 +1,68 @@ +# Analysis Request: Implement Shadow Order Verification + +**Status:** Completed +**Date:** 2025-12-20 +**Priority:** Medium + +--- + +## 1. User Description & Query +**Goal:** Verify if a Maker order (at the opposite side of the book) *would* have been filled if we had used it instead of a Taker order. +**Mechanism:** +1. When a Taker trade executes, record a "Shadow Order" at the *passive* price (e.g., if Taker Buying at Ask, Shadow Buy at Bid). +2. Check the market for the next 15 seconds. +3. If price crosses the Shadow Price, log "Success". If 15s passes without fill, log "Failed". + +## 2. Agent Summary +* **Objective:** Implement a lightweight "Shadow Order Simulator" inside `clp_hedger.py`. +* **Key Logic:** + * `Shadow Buy` at $3000 (Current Bid). *Fills if Future Ask <= $3000.* + * `Shadow Sell` at $3001 (Current Ask). *Fills if Future Bid >= $3001.* + * **Wait Time:** 15 seconds max. + +## 3. Main Analysis + +### 3.1 Logic Changes in `clp_hedger.py` + +#### A. Data Structure +Add `self.shadow_orders` list to `ScalperHedger`. +```python +self.shadow_orders = [ + { + 'id': 'shadow_123', + 'side': 'BUY', + 'price': 3000.0, + 'created_at': 1700000000, + 'expires_at': 1700000015 + } +] +``` + +#### B. Creation Trigger +Inside the `if oid:` block (successful Taker trade): +1. Determine **Passive Price**: + * If Taker BUY -> Passive Price = `levels['bid']` (Best Bid). + * If Taker SELL -> Passive Price = `levels['ask']` (Best Ask). +2. Append to `self.shadow_orders`. + +#### C. Verification Loop +Inside the main `while True` loop: +1. Iterate through `self.shadow_orders`. +2. **Check Fill:** + * Shadow BUY fills if `current_ask <= shadow_price`. (Someone sold into our bid). + * Shadow SELL fills if `current_bid >= shadow_price`. (Someone bought our ask). +3. **Check Expiry:** If `now > expires_at`, mark as FAILED (Price ran away). +4. **Log & Remove:** Log the result (`[SHADOW] SUCCESS/FAIL`) and remove from list. + +### 3.2 Technical Trade-offs +* **Pros:** Real-time, empirical data on "Maker Feasibility" without risking capital. +* **Cons:** Slight memory usage (negligible). Requires accurate `levels` data every loop. + +## 4. Conclusion +**Recommendation:** Proceed with implementation. This provides the exact "Cost of Waiting" vs "Gain from Spread" data requested. + +## 5. Implementation Plan +- [ ] **Step 1:** Initialize `self.shadow_orders` in `__init__`. +- [ ] **Step 2:** Add `check_shadow_orders(levels)` method. +- [ ] **Step 3:** Call `check_shadow_orders` in main loop. +- [ ] **Step 4:** Record new shadow order after `place_limit_order` (Taker) success. diff --git a/todo/data_needed_for_optymalization.md b/todo/data_needed_for_optymalization.md new file mode 100644 index 0000000..74c8675 --- /dev/null +++ b/todo/data_needed_for_optymalization.md @@ -0,0 +1,118 @@ +# Analysis Request: Data needed for system optimization + +**Status:** Completed +**Date:** 2025-12-20 +**Priority:** Medium + +--- + +## 1. User Description & Query +**Goal:** Check and analyze what kind of historical data is needed for further optimization of the system. +**Context:** Learning from the past how the system worked (good and bad) will help in the future. Assume that any kind of data publicly available can be used. +**Desired Behavior:** List of data which will help to improve now and in the future. + +### Specific Questions +1. Price data, what kind of? +2. CSV, DB? +3. Source of data (Hyperliquid, Uniswap)? +4. Other sources of data? Please propose. + +--- + +## 2. Agent Summary +* **Objective:** Define a comprehensive data strategy to support backtesting, parameter optimization, and performance analysis for the Uniswap CLP + Hyperliquid Hedger system. +* **Key Constraints:** + * **High Frequency:** Hedging logic runs on ~1s ticks. 1-minute candles are insufficient for simulating slippage and "whipsaw" events. + * **Dual Venue:** Must correlate Uniswap V3 (Spot/Liquidity) events with Hyperliquid (Perp/Hedge) actions. + * **Storage:** High-frequency data grows rapidly; format matters. + +## 3. Main Analysis + +### 3.1 Data Types Required + +To fully reconstruct and optimize the strategy, you need three distinct layers of data: + +#### A. Market Data (The "Environment") +1. **Tick-Level Trades (Hyperliquid):** + * *Why:* To simulate realistic slippage, fill probability, and exact trigger timing for the hedger. + * *Fields:* `timestamp_ms`, `price`, `size`, `side`, `liquidation (bool)`. +2. **Order Book Snapshots (Hyperliquid):** + * *Why:* To calculate "effective impact price" for large hedges. The mid-price might be $3000, but selling $50k might execute at $2998. + * *Frequency:* Every 1-5 seconds. +3. **Uniswap V3 Pool Events (Arbitrum):** + * *Why:* To track the exact "Health" of the CLP. Knowing when the price crosses a tick boundary is critical for "In Range" status. + * *Events:* `Swap` (Price changes), `Mint`, `Burn`. + +#### B. System State Data (The "Bot's Brain") +* *Why:* To understand *why* the bot made a decision. A trade might look bad in hindsight, but was correct given the data available at that millisecond. +* *Fields:* `timestamp`, `current_hedge_delta`, `target_hedge_delta`, `rebalance_threshold_used`, `volatility_metric`, `pnl_unrealized`, `pnl_realized`. + +#### C. External "Alpha" Data (Optimization Signals) +* **Funding Rates (Historical):** To optimize long/short bias. +* **Gas Prices (Arbitrum):** To optimize mint/burn timing (don't rebalance CLP if gas > expected fees). +* **Implied Volatility (Deribit/Derebit Options):** Compare realized vol vs. implied vol to adjust `DYNAMIC_THRESHOLD_MULTIPLIER`. + +### 3.2 Technical Options / Trade-offs + +| Option | Pros | Cons | Complexity | +| :--- | :--- | :--- | :--- | +| **A. CSV Files (Flat)** | Simple, human-readable, portable. Good for daily logs. | Slow to query large datasets. Hard to merge multiple streams (e.g., matching Uniswap swap to HL trade). | Low | +| **B. SQLite (Local DB)** | Single file, supports SQL queries, better performance than CSV. | Concurrency limits (one writer). Not great for massive tick data (TB scale). | Low-Medium | +| **C. Time-Series DB (InfluxDB / QuestDB)** | Optimized for high-frequency timestamps. Native downsampling. | Requires running a server/container. Overkill for simple analysis? | High | +| **D. Parquet / HDF5** | Extremely fast read/write for Python (Pandas). High compression. | Not human-readable. Best for "Cold" storage (backtesting). | Medium | + +### 3.3 Proposed Solution Design + +#### Architecture: "Hot" Logging + "Cold" Archival +1. **Live Logging (Hot):** Continue using `JSON` status files and `Log` files for immediate state. +2. **Data Collector Script:** A separate process (or async thread) that dumps high-frequency data into **daily CSVs** or **Parquet** files. +3. **Backtest Engine:** A Python script that loads these Parquet files to simulate "What if threshold was 0.08 instead of 0.05?". + +#### Data Sources +* **Hyperliquid:** Public API (Info) provides L2 snapshots and recent trade history. +* **Uniswap:** The Graph (Subgraphs) or RPC `eth_getLogs`. +* **Dune Analytics:** Great for exporting historical Uniswap V3 data (fees, volumes) to CSV for free/cheap. + +### 3.4 KPI & Performance Metrics +To truly evaluate "Success," we need more than just PnL. We need to compare against benchmarks. + +1. **NAV vs. Benchmark (HODL):** + * *Metric:* `(Current Wallet Value + Position Value) - (Net Inflows)` vs. `(Initial ETH * Current Price)`. + * *Goal:* Did we beat simply holding ETH? + * *Frequency:* Hourly. + +2. **Hedging Efficiency (Delta Neutrality):** + * *Metric:* `Net Delta Exposure = (Uniswap Delta + Hyperliquid Delta)`. + * *Goal:* Should be close to 0. A high standard deviation here means the bot is "loose" or slow. + * *Frequency:* Per-Tick (or aggregated per minute). + +3. **Cost of Hedge (The "Insurance Premium"):** + * *Metric:* `(Hedge Fees Paid + Funding Paid + Hedge Slippage) / Total Portfolio Value`. + * *Goal:* Keep this below the APR earned from Uniswap fees. + * *Frequency:* Daily. + +4. **Fee Coverage Ratio:** + * *Metric:* `Uniswap Fees Earned / Cost of Hedge`. + * *Goal:* Must be > 1.0. If < 1.0, the strategy is burning money to stay neutral. + * *Frequency:* Daily. + +5. **Impermanent Loss (IL) Realized:** + * *Metric:* Value lost due to selling ETH low/buying high during CLP rebalances vs. Fees Earned. + * *Frequency:* Per-Rebalance. + +## 4. Risk Assessment +* **Risk:** **Data Gaps.** If the bot goes offline, you miss market data. + * *Mitigation:* Use public historical APIs (like Hyperliquid's archive or Dune) to fill gaps, rather than relying solely on local recording. +* **Risk:** **Storage Bloat.** Storing every millisecond tick can fill a hard drive in weeks. + * *Mitigation:* Aggregate. Store "1-second OHLC" + "Tick Volume" instead of every raw trade, unless debugging specific slippage events. + +## 5. Conclusion +**Recommendation:** +1. **Immediate:** Start logging **Internal System State** (Thresholds, Volatility metrics) to a structured CSV (`hedge_metrics.csv`). You can't get this from public APIs later. +2. **External Data:** Don't build a complex scraper yet. Rely on downloading public data (Dune/Hyperliquid) when you are ready to backtest. +3. **Format:** Use **Parquet** (via Pandas) for storing price data. It's 10x faster and smaller than CSV. + +## 6. Implementation Plan +- [ ] **Step 1:** Create `tools/data_collector.py` to fetch and save public trade history (HL) daily. +- [ ] **Step 2:** Modify `clp_hedger.py` to append "Decision Metrics" (Vol, Threshold, Delta) to a `metrics.csv` every loop. +- [ ] **Step 3:** Use a notebook (Colab/Jupyter) to load `metrics.csv` and visualize "Threshold vs. Price Deviation". \ No newline at end of file diff --git a/todo/template._for_analisismd b/todo/template._for_analisismd new file mode 100644 index 0000000..8a0e931 --- /dev/null +++ b/todo/template._for_analisismd @@ -0,0 +1,70 @@ +# Analysis Request: [Insert Topic Here] + +**Status:** [Draft / Pending Analysis / Completed] +**Date:** [YYYY-MM-DD] +**Priority:** [Low / Medium / High] + +--- + +## 1. User Description & Query +*(User: Fill this section with your design ideas, questions, code snippets, or links to files/web resources. Be as specific as possible about the goal.)* + +### Context +* **Goal:** +* **Current Behavior:** +* **Desired Behavior:** + +### References +* **Files:** `[filename.py]`, `[path/to/module]` +* **Links:** `[url]` + +### Specific Questions / Hypothesis +1. +2. + +--- + +*(The sections below are to be filled by the AI Agent upon request)* + +## 2. Agent Summary +*(AI: Summarize the user's request to ensure alignment on the objective.)* + +* **Objective:** +* **Key Constraints:** +* **Scope:** + +## 3. Main Analysis +*(AI: Perform the deep dive here. Use codebase knowledge, logic, and simulations.)* + +### 3.1 Codebase Investigation +* **Affected Components:** +* **Data Flow Analysis:** +* **Current Limitation/Bug:** + +### 3.2 Technical Options / Trade-offs +| Option | Pros | Cons | Complexity | +| :--- | :--- | :--- | :--- | +| **A. [Strategy A]** | ... | ... | ... | +| **B. [Strategy B]** | ... | ... | ... | + +### 3.3 Proposed Solution Design +* **Architecture:** +* **Logic Changes:** +* **Edge Cases Considered:** + +## 4. Risk Assessment +*(AI: What could go wrong? Performance, Security, or Stability impacts.)* + +* **Risk 1:** [Description] -> *Mitigation:* [Strategy] + +## 5. Conclusion +*(AI: Final verdict and recommendation.)* + +* **Recommendation:** + +## 6. Implementation Plan +*(AI: Step-by-step checklist to execute the recommendation.)* + +- [ ] Step 1: +- [ ] Step 2: +- [ ] Step 3: