Skill: abhi152003/maxxit-0g (version 0.0.1)

--- emoji: ⚡ name: maxxit-0g version: 0.0.1 author: Maxxit description: Maxxit trading powered by 0G decentralized AI compute for portfolio-aware trade decisions and 0G decentralized storage for censorship-resistant alpha listings. Includes all DEX trading, market research, copy-trading, and alpha marketplace workflows from maxxit-lazy-trading. homepage: https://maxxit.ai disableModelInvocation: true requires: env: - MAXXIT_API_KEY - MAXXIT_API_URL metadata: openclaw: requiredEnv: - MAXXIT_API_KEY - MAXXIT_API_URL bins: - curl primaryCredential: MAXXIT_API_KEY --- # Maxxit 0G Trading Execute portfolio-aware AI trade decisions through 0G decentralized compute, then trade perpetual futures on Ostium, Aster DEX, and Avantis DEX through Maxxit's Lazy Trading API. Alpha listings can be stored on 0G decentralized storage so buyers receive an independent `rootHash` verification proof. ## Built-in Strategy Scripts The skill includes standalone Python strategy scripts. Use them when the user wants the agent to run a predefined trading system instead of manually specifying each trade. - `ema-strategy.py` - Trend-following EMA crossover on Binance klines using close prices. - `rsi-bollinger-strategy.py` - Mean-reversion system that waits for price to pierce a Bollinger Band and re-enter with RSI confirmation. - `donchian-adx-strategy.py` - Breakout system that trades Donchian channel breaks only when ADX confirms a strong trend regime. - `taker-strategy.py` - Aggressive Taker (Order Flow) HFT strategy. Analyzes Binance taker buy/sell ratios to detect aggressive market participants and catch rapid momentum shifts. - `mean-reversion-strategy.py` - RSI + Bollinger Band mean-reversion strategy. A technical approach using price exhaustion points optimized for high-frequency scalping in sideways or boring markets. - `breakout-strategy.py` - Volatility breakout strategy with ATR filter. Enters trades when price breaks out of a standard deviation channel while ATR confirms increasing volatility and momentum. - `vwap-strategy.py` - VWAP crossover institutional momentum strategy. Uses volume-weighted average price and EMA to confirm institutional trend alignment and confirm trade strength with volume. All scripts: - read Binance kline data directly from `https://api.binance.com/api/v3/klines` - use `MAXXIT_API_URL` and `MAXXIT_API_KEY` - execute through Maxxit programmatic trading endpoints - maintain per-symbol, per-venue state in the OpenClaw workspace Example invocations: ```bash python3 ema-strategy.py --symbol BTCUSDT --interval 5m --venue avantis python3 rsi-bollinger-strategy.py --symbol ETHUSDT --interval 5m --venue ostium python3 donchian-adx-strategy.py --symbol BTCUSDT --interval 15m --venue avantis ``` ## When to Use This Skill - User wants to execute trades on Ostium - User wants to execute trades on Aster DEX - User asks about their lazy trading account details - User wants to check their USDC/ETH balance - User wants to view their open positions or portfolio - User wants to see their closed position history or PnL - User wants to discover available trading symbols - User wants market research, a market summary, or a trade-focused research brief - User asks for a trade decision, "should I trade X", "make a decision", "AI decision", or "what does 0G think" - User wants a portfolio-aware AI trade recommendation - User wants their alpha listing stored on 0G decentralized storage - User wants a whole market snapshot for the trading purpose - User wants to open a new trading position (long/short) - User wants to close an existing position - User wants to set or modify take profit levels - User wants to set or modify stop loss levels - User wants to fetch current token/market prices - User mentions "lazy trade", "perps", "perpetuals", or "futures trading" - User wants to automate their trading workflow - User wants to copy-trade or mirror another trader's positions - User wants to discover other OpenClaw agents to learn from - User wants to see what trades top-performing traders are making - User wants to find high-impact-factor traders to replicate - User wants to sell their trading signals as alpha - User wants to browse or buy trustless alpha from ZK-verified traders - User wants to generate a ZK proof of their trading performance or flag a position as alpha - User mentions "alpha marketplace", "sell alpha", "buy alpha", or "ZK proof" ## Skill Maintenance - If the user asks OpenClaw to update this skill, run: ```bash npx clawhub@latest install maxxit-0g --force ``` --- ## ⚠️ DEX Routing Rules (Mandatory) 1. **Always ask venue first if unclear**: "Do you want to trade on Ostium, Aster, or Avantis?" 2. **Always state the active venue explicitly** in your response (e.g., "Using Ostium..." or "Using Aster..." or "Using Avantis..."). 3. **Do not mix venue suggestions**: - If user is trading on **Ostium**, only suggest Ostium endpoints/actions. - If user is trading on **Aster**, only suggest Aster endpoints/actions. - If user is trading on **Avantis**, only suggest Avantis endpoints/actions. 4. **Do not ask network clarification**: - **Ostium defaults to mainnet**, but if the user explicitly asks for **Ostium testnet / Arbitrum Sepolia**, honor that and pass `isTestnet: true` on Ostium endpoints. - **Aster is testnet-only** in this setup. - **Avantis is mainnet-only** (Base chain) in this setup. - Therefore do **not** ask "mainnet or testnet?" unless the user explicitly requests Ostium testnet. 5. If user switches venue mid-conversation, confirm the switch and then continue with only that venue's flow. --- ## ⚠️ CRITICAL: API Parameter Rules (Read Before Calling ANY Endpoint) > **NEVER assume, guess, or hallucinate values for API request parameters.** Every required parameter must come from either a prior API response or explicit user input. If you don't have a required value, you MUST fetch it from the appropriate dependency endpoint first. ### Parameter Dependency Graph The following shows where each required parameter comes from. **Always resolve dependencies before calling an endpoint.** | Parameter | Source | Endpoint to Fetch From | |-----------|--------|------------------------| | `userAddress` / `address` | `/user-details` response → `user_wallet` | `GET /user-details` | | `agentAddress` | `/user-details` response → `ostium_agent_address` | `GET /user-details` | | `tradeIndex` | `/open-position` response → `actualTradeIndex` **OR** `/positions` response → `tradeIndex` | `POST /open-position` or `POST /positions` | | `pairIndex` | `/positions` response → `pairIndex` **OR** `/symbols` response → symbol `id` | `POST /positions` or `GET /symbols` | | `entryPrice` | `/open-position` response → `entryPrice` **OR** `/positions` response → `entryPrice` | `POST /open-position` or `POST /positions` | | `market` / `symbol` | User specifies token **OR** `/symbols` response → `symbol` (e.g. `ETH/USD`) | User input or `GET /symbols` | | `side` | User specifies `"long"` or `"short"` | User input (required) | | `collateral` | User specifies the USDC amount | User input (required) | | `leverage` | User specifies the multiplier | User input (required) | | `takeProfitPercent` | User specifies (e.g., 0.30 = 30%) | User input (required) | | `stopLossPercent` | User specifies (e.g., 0.10 = 10%) | User input (required) | | `address` (for copy-trader-trades) | `/copy-traders` response → `creatorWallet` or `walletAddress` | `GET /copy-traders` | | `commitment` (Alpha) | `/alpha/agents` response → `commitment` | `GET /alpha/agents` | | `listingId` (Alpha) | `/alpha/listings` response → `listingId` | `GET /alpha/listings` | | `alpha`, `contentHash` (Alpha) | `/alpha/purchase` Phase 2 response → `alpha`, `contentHash` | `GET /alpha/purchase` + `X-Payment` header | | `txHash` (Alpha) | `/alpha/pay` response → `txHash` | `POST /alpha/pay` | ### Mandatory Workflow Rules 1. **Always call `/user-details` first** to get `user_wallet` (used as `userAddress`/`address`). Cache it for the session — it doesn't change. 2. **Treat `/user-details` as identity-first.** It always returns `user_wallet` for a valid API key, even if no lazy-trading agent exists yet. 3. **`/user-details` is sparse.** It omits fields that are empty, `null`, or `false`. Missing fields mean “not applicable” and should not be treated as an error or missing configuration by themselves. 4. **Only use `ostium_agent_address` when the venue needs an agent.** Ostium and Avantis require it. Zerodha does not. Aster only needs `user_wallet`, but `aster_configured` must be present and `true`. 5. **Never hardcode or guess wallet addresses.** They are unique per user and must come from `/user-details`. 6. **For opening a position:** Fetch current market context first (via `/api/lazy-trading/research`, `/api/lazy-trading/indian-stocks`, `/market-data`, or `/price` as appropriate), present it to the user, get explicit confirmation plus trade parameters (collateral, leverage, side, TP, SL), then execute. - **Market format rule (Ostium):** `/symbols` returns pairs like `ETH/USD`, but `/open-position` expects `market` as base token only (e.g. `ETH`). Convert by taking the base token before `/`. 7. **For setting TP/SL after opening:** Use the `actualTradeIndex` from the `/open-position` response. If you don't have it (e.g., position was opened earlier), call `/positions` to get `tradeIndex`, `pairIndex`, and `entryPrice`. 8. **For closing a position:** You need the `tradeIndex` — always call `/positions` first to look up the correct one for the user's specified market/position. 9. **Ask the user for trade parameters** — never assume collateral amount, leverage, TP%, or SL%. Present defaults but let the user confirm or override. 10. **Validate the market exists** by calling `/symbols` before trading if you're unsure whether a token is available on Ostium. 11. **For Alpha consumer flow:** Follow the exact order: `/alpha/agents` → `/alpha/listings` → `/alpha/purchase` (402) → `/alpha/pay` → `/alpha/purchase` (with `X-Payment`) → `/alpha/verify` → `/user-details` → `/alpha/execute`. Never skip steps. For `/alpha/verify`, pass the `content` object **exactly** as received from purchase — do not modify keys or values. ### Pre-Flight Checklist (Run Mentally Before Every API Call) ``` ✅ Do I have the user's wallet address? → If not, call /user-details ✅ Does this flow require an agent address? → If yes, call /user-details and verify ostium_agent_address is present ✅ Does this endpoint need a tradeIndex? → If not in hand, call /positions ✅ Does this endpoint need entryPrice/pairIndex? → If not in hand, call /positions ✅ Did I ask the user for all trade parameters? → collateral, leverage, side, TP%, SL% ✅ Is the market/symbol valid? → If unsure, call /symbols to verify ✅ (Alpha) Do I have commitment? → If not, call /alpha/agents ✅ (Alpha) Do I have listingId? → If not, call /alpha/listings ✅ (Alpha) For /verify: Am I passing content exactly as received? → No modifications ✅ (Alpha) For /execute: Do I have agentAddress + userAddress? → Call /user-details ``` --- ## Authentication All requests require an API key with prefix `lt_`. Pass it via: - Header: `X-[REDACTED_SECRET]` - Or: `[REDACTED_SECRET]` ## Market Research Workflow When the user asks for market research, use the Maxxit market research endpoint instead of writing the research from scratch. Endpoint: - `POST /api/lazy-trading/research` - `POST /api/lazy-trading/indian-stocks` for Indian equities research queries Rules: - Construct the `content` prompt from the user's ask. - Preserve the user's asset, timeframe, strategy, and risk focus. - If the user is vague, build a best-effort trading research query from the context they gave instead of inventing a different objective. - Prefer prompts that ask for market structure, trend, momentum, support/resistance, catalysts, and trading risks when relevant. - Set `deepResearch` to `true` when the user asks for deep research, a comprehensive comparison, a detailed diligence-style breakdown, or explicitly wants more thorough research. - Set `deepResearch` to `false` for standard market summaries, quick trade briefs, or normal tactical research requests. - For `POST /api/lazy-trading/indian-stocks`, OpenClaw must decide the request options from the user's query and should not ask the user to choose `chat_model`, `response_length`, or `thinking_level`. - Always send `question` plus the inferred request options: - `chat_model`: `analytical` or `strategic` - `response_length`: `short`, `medium`, or `long` - `thinking_level`: only include this when `chat_model` is `strategic` - Use `chat_model: "strategic"` when the user wants a trading plan, swing-trade setups, long/short ideas, entry zones, stop loss, target levels, timing for this week, or tactical positioning. In strategic mode, include `thinking_level` automatically: - use `balanced` by default - use `low` for quick, lightweight tactical asks - use `deep` only when the user explicitly asks for a more thoughtful or more detailed strategy answer - Use `chat_model: "analytical"` for screens, rankings, fundamentals, valuation, sector comparisons, capex-cycle beneficiaries, earnings quality, balance sheet analysis, and diligence-style research. Do not send `thinking_level` in analytical mode. - Infer `response_length` from the user’s ask: - use `short` for quick answers, concise trade ideas, and direct setup requests - use `medium` by default for normal research requests - use `long` for ranked lists, detailed comparisons, deep dives, or multi-factor explanations - If the user’s wording contains both analytical and tactical elements, prioritize the main deliverable. If the answer must provide actionable trade setups, choose `strategic`; if the answer is mainly screening, ranking, valuation, or fundamental comparison, choose `analytical`. - Summarize the response and format it for readability. Prompt construction examples: - User: "Research BTC for a swing long." - Query: `Analyze BTC for a swing-long setup. Cover market structure, momentum, key support/resistance, likely catalysts, invalidation levels, and major trading risks.` - User: "Give me market research on ETH for today." - Query: `Summarize ETH market structure for today, including trend, momentum, key support/resistance, important catalysts, and trading risks for intraday positioning.` - User: "Research SOL before I short it." - Query: `Analyze SOL for a potential short setup. Cover current market structure, weakness signals, resistance levels, downside levels to watch, catalysts, and key squeeze/invalidation risks.` Example call: ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/research" \ -H "X-[REDACTED_SECRET]" \ -H 'Content-Type: application/json' \ -d '{ "content": "Analyze BTC for a swing-long setup. Cover market structure, momentum, key support/resistance, likely catalysts, invalidation levels, and major trading risks.", "deepResearch": false }' ``` Indian stocks example: ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/indian-stocks" \ -H "X-[REDACTED_SECRET]" \ -H 'Content-Type: application/json' \ -d '{ "question": "Screen for Indian IT stocks with strong profit growth and low debt.", "chat_model": "analytical", "response_length": "medium" }' ``` Indian stocks tactical example: ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/indian-stocks" \ -H "X-[REDACTED_SECRET]" \ -H 'Content-Type: application/json' \ -d '{ "question": "Which Indian banking stocks look strongest for a swing trade this week? Give long ideas only, with entry zone, stop loss, target range, and the reasoning behind each setup.", "chat_model": "strategic", "response_length": "short", "thinking_level": "balanced" }' ``` When discussing Indian equities, NSE/BSE orders, holdings, targets, stop losses, or portfolio values: - use **Indian rupees** as the default unit - prefer `₹` in user-facing responses (for example, `₹2,450`, `₹1.2 lakh`) ## API Endpoints ## Ostium Programmatic Endpoints (`/api/lazy-trading/programmatic/*`) > All endpoints under `/api/lazy-trading/programmatic/*` are for **Ostium** unless explicitly prefixed with `/aster/`. ### Get User Details Retrieve lazy trading user information including wallet identity, agent status, Telegram connection, and trading preferences. ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/user-details" \ -H "X-[REDACTED_SECRET]" ``` **Response:** ```json { "success": true, "user_wallet": "0x...", "lazy_trading_ready": true, "agent": { "id": "agent-uuid", "name": "Lazy Trader - Username", "venue": "ostium", "status": "active" }, "telegram_user": { "id": 123, "telegram_user_id": "123456789", "telegram_username": "trader" }, "deployment": { "id": "deployment-uuid", "status": "active", "enabled_venues": ["ostium"] }, "trading_preferences": { "risk_tolerance": "medium", "trade_frequency": "moderate" }, "ostium_agent_address": "0x...", "aster_configured": true } ``` If the user has not set up a lazy-trading agent yet, `/user-details` still returns `200` and identity data, for example: ```json { "success": true, "user_wallet": "0x..." } ``` ### Get Available Symbols Retrieve all available trading symbols from the Ostium exchange. Use this to discover which symbols you can trade. ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/symbols" \ -H "X-[REDACTED_SECRET]" ``` **Response:** ```json { "success": true, "symbols": [ { "id": 0, "symbol": "BTC/USD", "group": "crypto", "maxLeverage": 150 }, { "id": 1, "symbol": "ETH/USD", "group": "crypto", "maxLeverage": 100 } ], "groupedSymbols": { "crypto": [ { "id": 0, "symbol": "BTC/USD", "group": "crypto", "maxLeverage": 150 }, { "id": 1, "symbol": "ETH/USD", "group": "crypto", "maxLeverage": 100 } ], "forex": [...] }, "count": 45 } ``` ### Get Account Balance Retrieve USDC and ETH balance for the user's Ostium wallet address. > **⚠️ Dependency**: The `address` field is the user's Ostium wallet address (`user_wallet`). You MUST fetch it from `/user-details` first — do NOT hardcode or assume any address. ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/balance" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d "{"address": "0x..."}" ``` **Response:** ```json { "success": true, "address": "0x...", "usdcBalance": "1000.50", "ethBalance": "0.045" } ``` ### Get Portfolio Positions Get all open positions for the user's Ostium trading account. **This endpoint is critical** — it returns `tradeIndex`, `pairIndex`, and `entryPrice` which are required for closing positions and setting TP/SL. > **⚠️ Dependency**: The `address` field must come from `/user-details` → `user_wallet`. NEVER guess it. > > **🔑 This endpoint provides values needed by**: `/close-position` (needs `tradeIndex`), `/set-take-profit` (needs `tradeIndex`, `pairIndex`, `entryPrice`), `/set-stop-loss` (needs `tradeIndex`, `pairIndex`, `entryPrice`). ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/positions" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d "{"address": "0x..."}" ``` **Request Body:** ```json { "address": "0x..." // REQUIRED — from /user-details → user_wallet. NEVER guess this. } ``` **Response:** ```json { "success": true, "positions": [ { "market": "BTC", "marketFull": "BTC/USD", "side": "long", "collateral": 100.0, "entryPrice": 95000.0, "leverage": 10.0, "tradeId": "12345", "tradeIndex": 2, "pairIndex": "0", "notionalUsd": 1000.0, "totalFees": 2.50, "stopLossPrice": 85500.0, "takeProfitPrice": 0.0 } ], "totalPositions": 1 } ``` > **Key fields to extract from each position:** > - `tradeIndex` — needed for `/close-position`, `/set-take-profit`, `/set-stop-loss` > - `pairIndex` — needed for `/set-take-profit`, `/set-stop-loss` > - `entryPrice` — needed for `/set-take-profit`, `/set-stop-loss` > - `side` — needed for `/set-take-profit`, `/set-stop-loss` ``` ### Get Position History Get trading history for a wallet. - `venue: "OSTIUM"` (default): uses Ostium history. - `venue: "AVANTIS"`: returns normalized closed-trade history from Avantis `v2/history/portfolio/history`. **Note:** The user's Ostium wallet address can be fetched from the [REDACTED_SECRET] endpoint (see Get Account Balance section above). ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/history" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{"venue":"OSTIUM","address":"0x...","count":50}' ``` **Request Body:** ```json { "venue": "OSTIUM", // Optional: "OSTIUM" (default) or "AVANTIS" "address": "0x...", // Required for OSTIUM; also accepted for AVANTIS as alias of userAddress "count": 50 // Number of recent orders to retrieve (default: 50) } ``` **Response:** ```json { "success": true, "history": [ { "market": "ETH", "side": "long", "collateral": 50.0, "leverage": 5, "price": 3200.0, "pnlUsdc": 15.50, "profitPercent": 31.0, "totalProfitPercent": 31.0, "rolloverFee": 0.05, "fundingFee": 0.10, "executedAt": "2025-02-10T15:30:00Z", "tradeId": "trade_123" } ], "count": 25, "venue": "OSTIUM" } ``` **Avantis history example (same `/history` endpoint):** ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/history" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{"venue":"AVANTIS","userAddress":"0x...","count":50}' ``` Returns normalized records like: `id`, `tradeId` (`<pairIndex>:<tradeIndex>`), `market`, `side`, `collateralUsdc`, `positionSizeUsdc`, `leverage`, `entryPrice`, `closePrice`, `usdcSentToTrader`, `grossPnlUsdc`, `closedAt`, `timestamp`. ### Open Position Open a new perpetual futures position on Ostium. > **⚠️ Dependencies — ALL must be resolved BEFORE calling this endpoint:** > 1. `agentAddress` → from `/user-details` → `ostium_agent_address` (NEVER guess) > 2. `userAddress` → from `/user-details` → `user_wallet` (NEVER guess) > 3. `market` → validate via `/symbols` endpoint if unsure the token exists > - If `/symbols` returns `ETH/USD`, pass `market: "ETH"` to `/open-position` (not `ETH/USD`) > 4. `side`, `collateral`, `leverage` → **ASK the user explicitly**, do not assume > > **📊 Recommended Pre-Trade Flow:** > 1. Call `/api/lazy-trading/research` for crypto trade research, or `/market-data` / `/price` for current market conditions > 2. Present the market context to the user (price, structure, momentum, volatility when available) > 3. Ask the user: "Do you want to proceed? Specify: collateral (USDC), leverage, long/short" > 4. Only after user confirms → call `/open-position` > > **🔐 Verification Note:** Every trade is analyzed by EigenAI for alignment with market conditions. Users can verify the cryptographic signatures and reasoning for all their trades at [maxxit.ai/openclaw](https://www.maxxit.ai/openclaw). > > **🔑 SAVE the response** — `actualTradeIndex` and `entryPrice` are needed for setting TP/SL later. ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/open-position" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "agentAddress": "0x...", "userAddress": "0x...", "market": "BTC", "side": "long", "collateral": 100, "leverage": 10 }' ``` **Request Body:** ```json { "agentAddress": "0x...", // REQUIRED — from /user-details → ostium_agent_address. NEVER guess. "userAddress": "0x...", // REQUIRED — from /user-details → user_wallet. NEVER guess. "market": "BTC", // REQUIRED — Base token only for Ostium (e.g. "ETH", not "ETH/USD"). Validate via /symbols if unsure. "side": "long", // REQUIRED — "long" or "short". ASK the user. "collateral": 100, // REQUIRED — Collateral in USDC. ASK the user. "leverage": 10, // Optional (default: 10). ASK the user. "deploymentId": "uuid...", // Optional — associated deployment ID "signalId": "uuid...", // Optional — associated signal ID "isTestnet": false // Optional. Set true only when user explicitly asks for Ostium testnet / Arbitrum Sepolia. } ``` **Response (IMPORTANT — save these values):** ```json { "success": true, "orderId": "order_123", "tradeId": "trade_abc", "transactionHash": "0x...", "txHash": "0x...", "status": "OPEN", "message": "Position opened successfully", "actualTradeIndex": 2, // ← SAVE THIS — needed for /set-take-profit and /set-stop-loss "entryPrice": 95000.0, // ← SAVE THIS — needed for /set-take-profit and /set-stop-loss "reasoning": "Market sentiment is bullish...", // EigenAI trade alignment analysis "llmSignature": "0x..." // Cryptographic signature for auditability } ``` ### Close Position Close an existing perpetual futures position on Ostium. > **⚠️ Dependencies — resolve BEFORE calling this endpoint:** > 1. `agentAddress` → from `/user-details` → `ostium_agent_address` > 2. `userAddress` → from `/user-details` → `user_wallet` > 3. `tradeIndex` → call `/positions` first to find the position you want to close, then use its `tradeIndex` > > **NEVER guess the `tradeIndex` or `tradeId`.** Always fetch from `/positions` endpoint. ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/close-position" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "agentAddress": "0x...", "userAddress": "0x...", "market": "BTC", "tradeId": "12345" }' ``` **Request Body:** ```json { "agentAddress": "0x...", // REQUIRED — from /user-details → ostium_agent_address. NEVER guess. "userAddress": "0x...", // REQUIRED — from /user-details → user_wallet. NEVER guess. "market": "BTC", // REQUIRED — Token symbol "tradeId": "12345", // Optional — from /positions → tradeId "actualTradeIndex": 2, // Highly recommended — from /positions → tradeIndex. NEVER guess. "isTestnet": false // Optional. Set true only when user explicitly asks for Ostium testnet / Arbitrum Sepolia. } ``` **Response:** ```json { "success": true, "result": { "txHash": "0x...", "market": "BTC", "closePnl": 25.50 }, "closePnl": 25.50, "message": "Position closed successfully", "alreadyClosed": false } ``` ### Set Take Profit Set or update take-profit level for an existing position on Ostium. > **⚠️ Dependencies — you need ALL of these before calling:** > 1. `agentAddress` → from `/user-details` → `ostium_agent_address` > 2. `userAddress` → from `/user-details` → `user_wallet` > 3. `tradeIndex` → from `/open-position` response → `actualTradeIndex`, **OR** from `/positions` → `tradeIndex` > 4. `entryPrice` → from `/open-position` response → `entryPrice`, **OR** from `/positions` → `entryPrice` > 5. `pairIndex` → from `/positions` → `pairIndex`, **OR** from `/symbols` → symbol `id` > 6. `takeProfitPercent` → **ASK the user** (default: 0.30 = 30%) > 7. `side` → from `/positions` → `side` ("long" or "short") > > **If you just opened a position:** Use `actualTradeIndex` and `entryPrice` from the `/open-position` response. > **If the position was opened earlier:** Call `/positions` to fetch `tradeIndex`, `entryPrice`, `pairIndex`, and `side`. ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/set-take-profit" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "agentAddress": "0x...", "userAddress": "0x...", "market": "BTC", "tradeIndex": 2, "takeProfitPercent": 0.30, "entryPrice": 90000, "pairIndex": 0 }' ``` **Request Body:** ```json { "agentAddress": "0x...", // REQUIRED — from /user-details. NEVER guess. "userAddress": "0x...", // REQUIRED — from /user-details. NEVER guess. "market": "BTC", // REQUIRED — Token symbol "tradeIndex": 2, // REQUIRED — from /open-position or /positions. NEVER guess. "takeProfitPercent": 0.30, // Optional (default: 0.30 = 30%). ASK the user. "entryPrice": 90000, // REQUIRED — from /open-position or /positions. NEVER guess. "pairIndex": 0, // REQUIRED — from /positions or /symbols. NEVER guess. "side": "long", // Optional (default: "long") — from /positions. "isTestnet": false // Optional. Set true only when user explicitly asks for Ostium testnet / Arbitrum Sepolia. } ``` **Response:** ```json { "success": true, "message": "Take profit set successfully", "tpPrice": 117000.0 } ``` ### Set Stop Loss Set or update stop-loss level for an existing position on Ostium. > **⚠️ Dependencies — identical to Set Take Profit. You need ALL of these before calling:** > 1. `agentAddress` → from `/user-details` → `ostium_agent_address` > 2. `userAddress` → from `/user-details` → `user_wallet` > 3. `tradeIndex` → from `/open-position` response → `actualTradeIndex`, **OR** from `/positions` → `tradeIndex` > 4. `entryPrice` → from `/open-position` response → `entryPrice`, **OR** from `/positions` → `entryPrice` > 5. `pairIndex` → from `/positions` → `pairIndex`, **OR** from `/symbols` → symbol `id` > 6. `stopLossPercent` → **ASK the user** (default: 0.10 = 10%) > 7. `side` → from `/positions` → `side` ("long" or "short") > > **If you just opened a position:** Use `actualTradeIndex` and `entryPrice` from the `/open-position` response. > **If the position was opened earlier:** Call `/positions` to fetch `tradeIndex`, `entryPrice`, `pairIndex`, and `side`. ```bash # Same dependency resolution as Set Take Profit (see above for full example) # Step 1: Get addresses from /user-details # Step 2: Get position details from /positions # Step 3: Set stop loss with user-specified stopLossPercent curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/set-stop-loss" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "agentAddress": "0x...", "userAddress": "0x...", "market": "BTC", "tradeIndex": 2, "stopLossPercent": 0.10, "entryPrice": 90000, "pairIndex": 0, "side": "long" }' ``` **Request Body:** ```json { "agentAddress": "0x...", // REQUIRED — from /user-details. NEVER guess. "userAddress": "0x...", // REQUIRED — from /user-details. NEVER guess. "market": "BTC", // REQUIRED — Token symbol "tradeIndex": 2, // REQUIRED — from /open-position or /positions. NEVER guess. "stopLossPercent": 0.10, // Optional (default: 0.10 = 10%). ASK the user. "entryPrice": 90000, // REQUIRED — from /open-position or /positions. NEVER guess. "pairIndex": 0, // REQUIRED — from /positions or /symbols. NEVER guess. "side": "long", // Optional (default: "long") — from /positions. "isTestnet": false // Optional. Set true only when user explicitly asks for Ostium testnet / Arbitrum Sepolia. } ``` **Response:** ```json { "success": true, "message": "Stop loss set successfully", "slPrice": 81000.0, "liquidationPrice": 85500.0, "adjusted": false } ``` ### Get All Market Data Retrieve the complete market snapshot from Ostium, including all symbols and their current metrics. This is useful for market-wide scanning or analysis in a single request. ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/market-data" \ -H "X-[REDACTED_SECRET]" ``` **Response:** ```json { "success": true, "data": [ { "id": 0, "symbol": "BTC/USD", "group": "crypto", "maxLeverage": 150, "metrics": { "price": "95000.12345678", "percent_change_24h": 2.45, "volatility": 0.032, "volume_24h": "45000000000.00000000", "market_cap": "1850000000000.00000000" }, "updated_at": "2026-02-14T08:30:00.000Z" }, ... ], "count": 45 } ``` ### Get Token Price Fetch the current market price for a token from Ostium price feed. ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/price?[REDACTED_SECRET]" \ -H "X-[REDACTED_SECRET]" ``` **Query Parameters:** | Parameter | Type | Required | Description | |-----------|-------|----------|-------------| | `token` | string | Yes | Token symbol to fetch price for (e.g., BTC, ETH, SOL) | | `isTestnet` | boolean | No | Use Ostium testnet / Arbitrum Sepolia when explicitly requested by the user | **Response:** ```json { "success": true, "token": "BTC", "price": 95000.0, "isMarketOpen": true, "isDayTradingClosed": false } ``` ### Discover Traders to Copy (Copy Trading — Step 1) Discover other OpenClaw Traders and top-performing traders to potentially copy-trade. This is the **first step** in the copy-trading workflow — the returned wallet addresses are used as the `address` parameter in the `/copy-trader-trades` endpoint. > **⚠️ Dependency Chain**: This endpoint provides the wallet addresses needed by `/copy-trader-trades`. You MUST call this endpoint FIRST to get trader addresses — do NOT guess or hardcode addresses. > > **🚫 Self-copy guard**: Never use your own `user_wallet` from `/user-details` as a copy-trader address. ```bash # Get all traders (OpenClaw + Leaderboard) curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/copy-traders" \ -H "X-[REDACTED_SECRET]" # Get only OpenClaw Traders (prioritized) curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/copy-traders?source=openclaw" \ -H "X-[REDACTED_SECRET]" # Get only Leaderboard traders with filters curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/copy-traders?source=leaderboard&minImpactFactor=50&minTrades=100" \ -H "X-[REDACTED_SECRET]" ``` **Query Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `source` | string | `all` | `openclaw` (OpenClaw agents only), `leaderboard` (top traders only), `all` (both) | | `limit` | int | 20 | Max results per tier (max 100) | | `minTrades` | int | — | Min trade count filter (leaderboard only) | | `minImpactFactor` | float | — | Min impact factor filter (leaderboard only) | **Response:** ```json { "success": true, "openclawTraders": [ { "agentId": "3dbc322f-...", "agentName": "OpenClaw Trader - 140226114735", "creatorWallet": [REDACTED_SECRET], "venue": "OSTIUM", "status": "PRIVATE", "isCopyTradeClub": false, "performance": { "apr30d": 0, "apr90d": 0, "aprSinceInception": 0, "sharpe30d": 0 }, "deployment": { "id": "dep-uuid", "status": "ACTIVE", "safeWallet": "0x...", "isTestnet": true } } ], "topTraders": [ { "walletAddress": "0xabc...", "totalVolume": "1500000.000000", "totalClosedVolume": "1200000.000000", "totalPnl": "85000.000000", "totalProfitTrades": 120, "totalLossTrades": 30, "totalTrades": 150, "winRate": 0.80, "lastActiveAt": "2026-02-15T10:30:00.000Z", "scores": { "edgeScore": 0.82, "consistencyScore": 0.75, "stakeScore": 0.68, "freshnessScore": 0.92, "impactFactor": 72.5 }, "updatedAt": "2026-02-17T06:00:00.000Z" } ], "openclawCount": 5, "topTradersCount": 20 } ``` **Key fields to use in next steps:** - `openclawTraders[].creatorWallet` → use as `address` in `/copy-trader-trades` - `topTraders[].walletAddress` → use as `address` in `/copy-trader-trades` - Exclude any address equal to your own `/user-details.user_wallet` ### Get Trader's Recent Trades (Copy Trading — Step 2) Fetch recent on-chain trades for a specific trader address. This queries the Ostium subgraph in real-time for fresh trade data. > **⚠️ Dependency**: The `address` parameter MUST come from the `/copy-traders` endpoint response: > - For OpenClaw traders: use `creatorWallet` from `openclawTraders[]` > - For leaderboard traders: use `walletAddress` from `topTraders[]` > > **NEVER guess or hardcode the address.** Always call `/copy-traders` first. ```bash # Step 1: Discover traders first TRADER_ADDRESS=$(curl -s -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/copy-traders?source=openclaw" \ -H "X-[REDACTED_SECRET]" | jq -r '.openclawTraders[0].creatorWallet') # Step 2: Fetch their recent trades curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/copy-trader-trades?address=${TRADER_ADDRESS}" \ -H "X-[REDACTED_SECRET]" # With custom lookback and limit curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/copy-trader-trades?address=${TRADER_ADDRESS}&hours=48&limit=50" \ -H "X-[REDACTED_SECRET]" ``` **Query Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `address` | string | *required* | Trader wallet address (from `/copy-traders`) | | `limit` | int | 20 | Max trades to return (max 50) | | `hours` | int | 24 | Lookback window in hours (max 168 / 7 days) | **Response:** ```json { "success": true, "traderAddress": [REDACTED_SECRET], "trades": [ { "tradeId": "0x123...", "side": "LONG", "tokenSymbol": "BTC", "pair": "BTC/USD", "collateral": 500.00, "leverage": 10.0, "entryPrice": 95000.50, "takeProfitPrice": 100000.00, "stopLossPrice": 90000.00, "timestamp": "2026-02-17T14:30:00.000Z" } ], "count": 5, "lookbackHours": 24 } ``` **Trade Field Descriptions:** | Field | Description | |-------|-------------| | `side` | `"LONG"` or `"SHORT"` — the trade direction | | `tokenSymbol` | Token being traded (e.g., `BTC`, `ETH`) | | `pair` | Full pair label (e.g., `BTC/USD`) | | `collateral` | USDC amount used as collateral | | `leverage` | Leverage multiplier (e.g., 10.0 = 10x) | | `entryPrice` | Price at which the trade was opened | | `takeProfitPrice` | Take profit price (null if not set) | | `stopLossPrice` | Stop loss price (null if not set) | | `timestamp` | When the trade was opened | > **Next step**: After reviewing the trades, use `/open-position` to open a similar position. You'll need your own `agentAddress` and `userAddress` from `/user-details`. ## Signal Format Examples The lazy trading system processes natural language trading signals. Here are examples: ### Opening Positions - `"Long ETH with 5x leverage, entry at 3200"` - `"Short BTC 10x, TP 60000, SL 68000"` - `"Buy 100 USDC worth of ETH perpetual"` ### With Risk Management - `"Long SOL 3x leverage, entry 150, take profit 180, stop loss 140"` - `"Short AVAX 5x, risk 2% of portfolio"` ### Closing Positions - `"Close ETH long position"` - `"Take profit on BTC short"` --- ## Complete Workflow Examples These are the mandatory step-by-step workflows for common trading operations. **Follow these exactly.** ### 0G Decision Workflow Use this workflow when the user says "should I trade [token]", "make a decision", "AI decision", "what does 0G think about [token]", or asks for a portfolio-aware recommendation. ``` Step 1: GET /user-details → Extract: user_wallet and deploymentId/deployment_id if present → If deploymentId is not returned directly, use the active lazy-trading deployment ID from the setup/status context Step 2: POST /api/lazy-trading/research → Run market research for the token → Summarize the output into 2-3 sentences → Include all relevant market data in this summary because /alpha/0g-decision does not fetch market data separately Step 3: POST /alpha/0g-decision → Body: { "deploymentId": "{deploymentId from Step 1}", "tokenSymbol": "{token}", "marketResearchSummary": "{market + research summary from Step 2}" } → Present to user: 0G Compute Decision — {TOKEN} Should Trade : YES / NO Side : long / short / none Confidence : X% Reasoning : {reasoning} Sponsored : true Step 4: Ask — "Do you want me to act on this decision?" → NO → Done. → YES → Continue to normal open-position workflow using the side from Step 3 → Still ask user for required execution parameters that 0G did not provide, especially collateral, leverage, TP, and SL Step 5 (after position opens): Ask — "Would you like to list this trade as alpha on 0G storage?" → NO → Done. → YES → Run Alpha Producer workflow: POST /alpha/generate-proof Poll /alpha/proof-status until VERIFIED POST /alpha/flag If /alpha/flag returns ogStorage.rootHash, show it: "Alpha listed! Listing ID : {listingId} 0G Storage Root: {rootHash} Buyers receive this root hash with their purchase receipt for independent verification on 0G." If ogStorage.rootHash is null: "Listed on Maxxit DB (0G storage unavailable)." ``` ### Workflow 1: Opening a New Position (Full Flow) ``` Step 1: GET /user-details → Extract: user_wallet (→ userAddress), ostium_agent_address (→ agentAddress) → Cache these for the session Step 2: GET /symbols → Verify the user's requested token is available on Ostium → Extract exact symbol string and maxLeverage → Convert pair format to market token for /open-position: "ETH/USD" -> "ETH" Step 3: POST /api/lazy-trading/research (or GET /market-data or GET /price for current context) → Get trade context: market structure, momentum, support/resistance, catalysts, and current price → Present this data to the user: "BTC is trading around $95,000 with bullish structure and clear support/resistance levels. Do you want to proceed?" Step 4: ASK the user for trade parameters → "Please confirm: collateral (USDC), leverage, long or short?" → "Would you like to set TP and SL? If so, what percentages?" → Wait for explicit user confirmation before proceeding Step 5: POST /open-position → Use agentAddress and userAddress from Step 1 → Use market, side, collateral, leverage from Step 4 → IMPORTANT: Pass market as base token only (e.g. ETH), not pair format (ETH/USD) → SAVE the response: actualTradeIndex and entryPrice Step 6 (if user wants TP/SL): POST /set-take-profit and/or POST /set-stop-loss → Use tradeIndex = actualTradeIndex from Step 5 → Use entryPrice from Step 5 → For pairIndex, use the symbol id from Step 2 or call /positions → Use takeProfitPercent/stopLossPercent from Step 4 Step 7: ASK — "Would you like to list this trade as alpha on the marketplace?" → If user says NO → Done. → If user says YES → Continue to Step 8. → Also ask: "What price in USDC would you like to charge?" (e.g. 5 USDC) Step 8: POST /alpha/generate-proof → Body: { "tradeId": "{tradeId from Step 5}", "autoProcess": false } → tradeId comes from the /open-position response → autoProcess: false queues the proof for the worker (~3-5 min) → SAVE: proofId from the response Step 9: Wait for proof verification → If autoProcess was true and response has status: "VERIFIED" → go to Step 10 → If autoProcess was false or status is still PENDING/PROVING: Poll GET /alpha/proof-status?proofId={proofId} every 10 seconds → Wait until status === "VERIFIED" → If status === "FAILED" → inform the user and stop Step 10: POST /alpha/flag → Body: { "proofId": "{proofId from Step 8}", "priceUsdc": {price from Step 7}, "token": "{market from Step 5, e.g. ETH}", "side": "{side from Step 5, e.g. long}", "leverage": {leverage from Step 5} } → Show user the response: listingId, tradeId, proofMetrics → "Your trade is now listed as alpha! Listing ID: {listingId}" ``` ### Workflow 2: Closing an Existing Position ``` Step 1: GET /user-details → Extract: user_wallet, ostium_agent_address Step 2: POST /positions (address = user_wallet from Step 1) → List all open positions → Present them to the user if multiple: "You have 3 open positions: BTC long, ETH short, SOL long. Which one do you want to close?" → Extract the tradeIndex for the position to close Step 3: POST /close-position → Use agentAddress and userAddress from Step 1 → Use market and actualTradeIndex from Step 2 → Show the user the closePnl from the response ``` ### Workflow 3: Setting TP/SL on an Existing Position ``` Step 1: GET /user-details → Extract: user_wallet, ostium_agent_address Step 2: POST /positions (address = user_wallet from Step 1) → Find the target position → Extract: tradeIndex, entryPrice, pairIndex, side Step 3: ASK the user → "Position: BTC long at $95,000. Current TP: none, SL: $85,500." → "What TP% and SL% would you like to set?" Step 4: POST /set-take-profit and/or POST /set-stop-loss → Use ALL values from Steps 1-3 — NEVER guess any of them ``` ### Workflow 4: Checking Portfolio & Market Overview ``` Step 1: GET /user-details → Extract: user_wallet Step 2: POST /balance (address = user_wallet) → Show the user their USDC and ETH balances Step 3: POST /positions (address = user_wallet) → Show all open positions with PnL details Step 4 (optional): GET /market-data → Show market conditions for tokens they hold ``` ### Workflow 5: Copy-Trading Another OpenClaw Agent (Full Flow) ``` Step 1: GET /copy-traders?source=openclaw → Discover other OpenClaw Trader agents → Extract: creatorWallet from the trader you want to copy → Exclude your own wallet (`/user-details.user_wallet`) if it appears → IMPORTANT: This is a REQUIRED first step — you cannot call /copy-trader-trades without an address from this endpoint Step 2: GET /copy-trader-trades?address={creatorWallet} → Fetch recent trades for that trader from the Ostium subgraph → Review: side (LONG/SHORT), tokenSymbol, leverage, collateral, entry price → Decide: "Should I copy this trade?" → DEPENDENCY: The address param comes from Step 1 (creatorWallet or walletAddress) Step 3: GET /user-details → Get YOUR OWN userAddress (user_wallet) and agentAddress (ostium_agent_address) → These are needed to execute your own trade Step 4: POST /open-position → Mirror the trade from Step 2 using your own addresses from Step 3: - market = tokenSymbol from the copied trade - side = side from the copied trade (LONG/SHORT → long/short) - collateral = decide based on your own risk tolerance - leverage = match the copied trader's leverage or adjust → SAVE: actualTradeIndex and entryPrice from response Step 5 (optional): POST /set-take-profit and/or POST /set-stop-loss → Use actualTradeIndex and entryPrice from Step 4 → Match the copied trader's TP/SL ratios or set your own ``` **Dependency Chain Summary:** ``` /copy-traders → provides address → /copy-trader-trades → provides trade details /user-details → provides your addresses → /open-position → copies the trade ``` --- ## Automated Trading Strategies Maxxit provides specialized scripts for different market conditions. These scripts require dynamic parameters passed via command line. ### Execution Policy - **Dynamic Arguments**: Scripts MUST be invoked with `--symbol` and `--venue`. - **Agent Responsibility**: If the user asks to start a strategy but does not provide the symbol (e.g., "BTC/USD") or the venue (e.g., "AVANTIS"), the agent MUST ask the user for the missing information before executing the script. - **Example Command**: `python taker-strategy.py --symbol BTC/USD --venue AVANTIS` ### 1. Aggressive Taker (HFT / Order Flow) - **Script**: `taker-strategy.py` - **Usage**: `python taker-strategy.py --symbol <SYMBOL> --venue <VENUE>` - **Logic Summary**: Monitors the "Taker Buy Ratio" on Binance. When aggressive buyers (takers) dominate sellers beyond a threshold (0.60), it signals a high-conviction momentum move. - **Best For**: Capturing rapid price changes in high-volume environments (Active Scalping). ### 2. Mean Reversion (Sideways / Range) - **Script**: `mean-reversion-strategy.py` - **Usage**: `python mean-reversion-strategy.py --symbol <SYMBOL> --venue <VENUE>` - **Logic Summary**: Combines RSI (extreme oversold/overbought) with Bollinger Band touches. It identifies "exhaustion" points where the price is likely to bounce back to the average. - **Best For**: Range-bound or sideways markets where there is no clear trend. ### 3. Volatility Breakout (Momentum) - **Script**: `breakout-strategy.py` - **Usage**: `python breakout-strategy.py --symbol <SYMBOL> --venue <VENUE>` - **Logic Summary**: Enters a trade only when price breaks out of a standard deviation channel (Bollinger Bands) *and* volatility (ATR) is increasing. This filters out "fake" breakouts. - **Best For**: Catching the start of a strong trend after a period of consolidation. ### 4. VWAP Crossover (Institutional Momentum) - **Script**: `vwap-strategy.py` - **Usage**: `python vwap-strategy.py --symbol <SYMBOL> --venue <VENUE>` - **Logic Summary**: Uses Volume Weighted Average Price (VWAP) combined with a 20 EMA. A "Long" is triggered when price is above both the VWAP and the EMA, signaling that both volume and time-weighted momentum are positive. - **Best For**: Intraday momentum trading and confirming trend strength with volume. --- ## Aster DEX (BNB Chain) Endpoints > Aster DEX is a perpetual futures exchange on BNB Chain. Use Aster endpoints when the user wants to trade on BNB Chain. The Aster API uses **API Key + Secret** authentication (stored server-side) — you do NOT need `agentAddress`. You only need `userAddress` from `/user-details`. ### Venue Selection | Venue | Chain | Symbol Format | Auth Required | When to Use | |-------|-------|--------------|---------------|-------------| | **Ostium** | Arbitrum (mainnet by default, testnet on explicit request) | `BTC`, `ETH` | `agentAddress` + `userAddress` | Default for most trades | | **Aster** | BNB Chain (testnet only) | `BTCUSDT`, `ETHUSDT` | `userAddress` only | When user specifies BNB Chain or Aster | | **Avantis** | Base (mainnet only) | Base token for orders (e.g. `BTC`), pair format in symbols/positions (e.g. `BTC/USD`) | `agentAddress` + `userAddress` | When user specifies Base chain or Avantis | > **Network behavior rule:** Do not ask users to choose mainnet/testnet for these venues by default. Ostium uses mainnet unless the user explicitly asks for testnet / Arbitrum Sepolia. Aster is fixed to testnet, and Avantis is fixed to Base mainnet. **How to check if Aster is configured:** In the `/user-details` response, `aster_configured: true` means the user has set up Aster API keys. If `false`, direct them to set up Aster at maxxit.ai/openclaw. ### Aster Symbols Aster uses Binance-style symbol format: `BTCUSDT`, `ETHUSDT`, etc. The API auto-appends `USDT` if you pass just `BTC`. ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/aster/symbols" \ -H "X-[REDACTED_SECRET]" ``` **Response:** ```json { "success": true, "symbols": [ { "symbol": "BTCUSDT", "baseAsset": "BTC", "quoteAsset": "USDT", "pricePrecision": 2, "quantityPrecision": 3, "contractType": "PERPETUAL", "status": "TRADING" } ], "count": 50 } ``` ### Aster Price ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/aster/price?token=BTC" \ -H "X-[REDACTED_SECRET]" ``` **Response:** ```json { "success": true, "token": "BTC", "symbol": "BTCUSDT", "price": 95000.50 } ``` ### Aster Market Data ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/aster/market-data?symbol=BTC" \ -H "X-[REDACTED_SECRET]" ``` ### Aster Balance ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/aster/balance" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "userAddress": "0x..." }' ``` **Request Body:** ```json { "userAddress": "0x..." // REQUIRED — from /user-details → user_wallet. NEVER guess. } ``` **Response:** ```json { "success": true, "balance": 1000.50, "availableBalance": 800.25, "unrealizedProfit": 50.10 } ``` ### Aster Positions ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/aster/positions" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "userAddress": "0x..." }' ``` **Response:** ```json { "success": true, "positions": [ { "symbol": "BTCUSDT", "positionAmt": 0.01, "entryPrice": 95000.0, "markPrice": 96000.0, "unrealizedProfit": 10.0, "liquidationPrice": 80000.0, "leverage": 10, "side": "long" } ], "count": 1 } ``` ### Aster History (All Orders) Fetch full order history for a symbol (includes active, canceled, and filled orders) from Aster. ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/aster/history" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "userAddress": "0x...", "symbol": "BTC", "limit": 100 }' ``` **Request Body:** ```json { "userAddress": "0x...", // REQUIRED — from /user-details → user_wallet "symbol": "BTC", // REQUIRED — token or full symbol (BTC or BTCUSDT) "limit": 100, // Optional — default depends on exchange (max 1000) "orderId": 12345, // Optional — fetch from this orderId onward "startTime": 1709251200000, // Optional — ms timestamp "endTime": 1709856000000 // Optional — ms timestamp } ``` > `POST /api/lazy-trading/programmatic/aster/history` now proxies to Aster `/fapi/v3/allOrders`. > Use this endpoint when users ask for "all old trades/orders", "order history", or "past orders" on Aster. ### Aster Open Position > **📋 LLM Pre-Call Checklist — Ask the user these questions before calling this endpoint:** > 1. **Symbol**: "Which token do you want to trade?" (e.g. BTC, ETH, SOL) > 2. **Side**: "Long or short?" > 3. **Quantity**: "How much [TOKEN] do you want to trade?" — get the answer in base asset units (e.g. `0.01 BTC`, `0.5 ETH`). > 4. **Leverage**: "What leverage? (e.g. 10x)" > 5. **Order type**: "Market order or limit order?" (default: MARKET). If LIMIT, also ask for the limit price. > > **Aster requires `quantity` (base asset) for open-position. Do not use collateral.** > **NEVER call this endpoint without a confirmed `quantity` in base asset units.** ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/aster/open-position" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "userAddress": "0x...", "symbol": "BTC", "side": "long", "quantity": 0.01, "leverage": 10 }' ``` **Request Body:** ```json { "userAddress": "0x...", // REQUIRED — from /user-details → user_wallet. NEVER guess. "symbol": "BTC", // REQUIRED — Token name or full symbol (BTCUSDT). ASK the user. "side": "long", // REQUIRED — "long" or "short". ASK the user. "quantity": 0.01, // REQUIRED — Position size in BASE asset (e.g. 0.01 BTC). ASK the user. "leverage": 10, // Optional — Leverage multiplier. ASK the user. "type": "MARKET", // Optional — "MARKET" (default) or "LIMIT". ASK the user. "price": 95000 // Required only for LIMIT orders. ASK the user if type is LIMIT. } ``` > ⚠️ **IMPORTANT:** `quantity` must always be specified in the **base asset** (e.g. `0.01` for 0.01 BTC). > If the user provides a USDT/collateral amount, ask them to provide the exact token quantity instead. > Do not convert collateral to quantity in this workflow. **Response (IMPORTANT — save these values):** ```json { "success": true, "orderId": 12345678, "symbol": "BTCUSDT", "side": "BUY", "status": "FILLED", "avgPrice": "95000.50", "executedQty": "0.010", "message": "Position opened: long BTCUSDT" } ``` ### Aster Close Position ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/aster/close-position" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "userAddress": "0x...", "symbol": "BTC" }' ``` **Request Body:** ```json { "userAddress": "0x...", // REQUIRED "symbol": "BTC", // REQUIRED "quantity": 0.005 // Optional — omit to close full position } ``` ### Aster Set Take Profit ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/aster/set-take-profit" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "userAddress": "0x...", "symbol": "BTC", "takeProfitPercent": 0.30, "entryPrice": 95000, "side": "long" }' ``` **Request Body (two options):** ```json { "userAddress": "0x...", "symbol": "BTC", "stopPrice": 123500 // Option A: exact trigger price } ``` ```json { "userAddress": "0x...", "symbol": "BTC", "takeProfitPercent": 0.30, // Option B: percentage (0.30 = 30%) "entryPrice": 95000, "side": "long" } ``` ### Aster Set Stop Loss Same pattern as take profit: ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/aster/set-stop-loss" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "userAddress": "0x...", "symbol": "BTC", "stopLossPercent": 0.10, "entryPrice": 95000, "side": "long" }' ``` ### Aster Change Leverage ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/aster/change-leverage" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "userAddress": "0x...", "symbol": "BTC", "leverage": 20 }' ``` ### Aster Parameter Dependency Graph | Parameter | Source | How to Get | |-----------|--------|-----------| | `userAddress` | `/user-details` → `user_wallet` | `GET /user-details` | | `aster_configured` | `/user-details` → `aster_configured` | `GET /user-details` (must be `true`) | | `symbol` | User specifies token | User input (auto-resolved: `BTC` → `BTCUSDT`) | | `side` | User specifies `"long"` or `"short"` | User input (required) | | `quantity` | User specifies in base asset units (e.g. `0.01 BTC`) | User input (required). If user provides USDT/collateral amount, ask for quantity instead. Do not calculate in the workflow. | | `leverage` | User specifies | User input | | `entryPrice` | `/aster/positions` → `entryPrice` | From position data | | `stopPrice` | User specifies or calculated from percent | User input or calculated | ### Aster Workflow: Open Position on BNB Chain ``` Step 1: GET /user-details → Extract: user_wallet → Check: aster_configured == true (if false, tell user to set up Aster at maxxit.ai/openclaw) Step 2: GET /aster/symbols → Verify the token is available on Aster Step 3: GET /aster/price?token=BTC → Get current price, present to user Step 4: ASK the user for ALL trade parameters → "Which token?" (e.g. BTC, ETH, SOL) → "Long or short?" → "How much [TOKEN] do you want to buy/sell?" — collect answer in BASE asset units (e.g. 0.01 BTC) • If user gives a USDT/collateral amount, ask them to provide token quantity instead. → "Leverage? (e.g. 10x)" → "Market or limit order?" — if LIMIT, also ask for the limit price Step 5: POST /aster/open-position → Use userAddress from Step 1 → Use symbol, side, quantity (base asset), leverage from Step 4 → SAVE orderId and avgPrice from response Step 6 (if user wants TP/SL): POST /aster/set-take-profit and/or POST /aster/set-stop-loss → Use entryPrice = avgPrice from Step 5 → Use side from Step 4 → Ask user for takeProfitPercent / stopLossPercent (or exact stopPrice) ``` ### Aster Workflow: Close Position ``` Step 1: GET /user-details → Extract user_wallet Step 2: POST /aster/positions (userAddress = user_wallet) → Show positions to user, let them pick which to close Step 3: POST /aster/close-position → Pass userAddress and symbol → Omit quantity to close full position ``` --- ## Avantis DEX (Base Chain) Endpoints > Avantis DEX is a perpetual futures exchange on Base chain. Use Avantis endpoints when the user wants to trade on Base. Avantis uses **delegation-based auth** (same pattern as Ostium) — you need both `agentAddress` and `userAddress` from `/user-details`. **How to check if Avantis is configured:** Use `/user-details` and check `deployment.enabled_venues`. If it includes `"AVANTIS"`, Avantis is enabled for the current deployment. If not, direct the user to enable Avantis at maxxit.ai/openclaw. ### Avantis Symbols Avantis symbols are returned in pair format (e.g. `BTC/USD`, `ETH/USD`). The API endpoint maps the service's `/markets` route. ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/avantis/symbols" \ -H "X-[REDACTED_SECRET]" ``` **Response:** ```json { "success": true, "markets": [ { "pairIndex": 0, "symbol": "BTC/USD", "group": "crypto" }, { "pairIndex": 1, "symbol": "ETH/USD", "group": "crypto" } ], "count": 50 } ``` ### Avantis Get Token Price Fetch the latest price for a specific token on Avantis. ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/avantis/price?token=BTC" \ -H "X-[REDACTED_SECRET]" ``` **Query Parameters:** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `token` | string | Yes | Token symbol or pair (e.g. `BTC` or `BTC/USD`) | **Response:** ```json { "success": true, "token": "BTC", "market": "BTC/USD", "pairIndex": 0, "price": 95000.12 } ``` ### Avantis Balance ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/avantis/balance" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "userAddress": "0x..." }' ``` **Request Body:** ```json { "userAddress": "0x..." // REQUIRED — from /user-details → user_wallet. NEVER guess. } ``` **Response:** ```json { "success": true, "usdcBalance": "1500.25", "ethBalance": "0.05" } ``` ### Avantis Positions ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/avantis/positions" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "userAddress": "0x...", "agentAddress": "0x..." }' ``` **Response:** ```json { "success": true, "positions": [ { "market": "BTC/USD", "marketFull": "BTC/USD", "side": "long", "collateral": 100.0, "entryPrice": 95000.0, "leverage": 10.0, "tradeId": "0:2", "tradeIndex": 2, "pairIndex": 0 } ], "totalPositions": 1 } ``` ### Avantis Open Position > **⚠️ Dependencies:** > 1. `agentAddress` → from `/user-details` → `ostium_agent_address` (shared agent wallet; NEVER guess) > 2. `userAddress` → from `/user-details` → `user_wallet` (NEVER guess) > 3. `market` → validate via `/avantis/symbols`. Use base token only (e.g. `BTC`, not `BTC/USD`) > 4. `side`, `collateral`, `leverage` → **ASK the user explicitly** > > **Avantis uses `collateral` (USDC amount), similar to Ostium.** > > **TP/SL can be set at open (`takeProfitPercent` / `stopLossPercent`) or updated later via `/avantis/update-sl-tp`.** ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/avantis/open-position" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "agentAddress": "0x...", "userAddress": "0x...", "market": "BTC", "side": "long", "collateral": 100, "leverage": 10, "takeProfitPercent": 0.30, "stopLossPercent": 0.10 }' ``` **Request Body:** ```json { "agentAddress": "0x...", // REQUIRED — from /user-details → ostium_agent_address (shared wallet). NEVER guess. "userAddress": "0x...", // REQUIRED — from /user-details → user_wallet. NEVER guess. "market": "BTC", // REQUIRED — Base token only (e.g. "ETH", not "ETH/USD") "side": "long", // REQUIRED — "long" or "short". ASK the user. "collateral": 100, // REQUIRED — Collateral in USDC. ASK the user. "leverage": 10, // Optional (default: 10). ASK the user. "takeProfitPercent": 0.30, // Optional — set TP at open. ASK the user. "stopLossPercent": 0.10 // Optional — set SL at open. ASK the user. } ``` **Response:** ```json { "success": true, "txHash": "0x...", "actualTradeIndex": 5, "entryPrice": 95000.0, "slSet": true, "tpSet": true, "message": "Trade submitted on Avantis", "result": { "market": "BTC", "side": "long", "collateral": 100, "leverage": 10, "slConfigured": true, "tpConfigured": true, "tpPrice": 123500.0, "slPrice": 85500.0 } } ``` ### Avantis Close Position ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/avantis/close-position" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "agentAddress": "0x...", "userAddress": "0x...", "market": "BTC" }' ``` **Request Body:** ```json { "agentAddress": "0x...", // REQUIRED — from /user-details. NEVER guess. "userAddress": "0x...", // REQUIRED — from /user-details. NEVER guess. "market": "BTC", // REQUIRED — Token symbol "tradeId": "0:2", // Optional — preferred composite ID from /avantis/positions (pairIndex:tradeIndex) "actualTradeIndex": 2 // Recommended — from /avantis/positions → tradeIndex } ``` ### Avantis Update SL/TP > **TP/SL can be set at open time (via `takeProfitPercent`/`stopLossPercent` in open-position), or updated after opening using this endpoint.** ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/avantis/update-sl-tp" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "agentAddress": "0x...", "userAddress": "0x...", "market": "BTC", "takeProfitPercent": 0.30, "stopLossPercent": 0.10 }' ``` **Request Body:** ```json { "agentAddress": "0x...", // REQUIRED — from /user-details. NEVER guess. "userAddress": "0x...", // REQUIRED — from /user-details. NEVER guess. "market": "BTC", // REQUIRED — Token symbol "tradeIndex": 0, // Optional — specific trade index from /avantis/positions "takeProfitPrice": 100000, // Absolute TP price (use this OR takeProfitPercent) "stopLossPrice": 80000, // Absolute SL price (use this OR stopLossPercent) "takeProfitPercent": 0.30, // TP as % from entry (0.30 = 30%). Use this OR takeProfitPrice. "stopLossPercent": 0.10 // SL as % from entry (0.10 = 10%). Use this OR stopLossPrice. } ``` **Response:** ```json { "success": true, "txHash": "0x...", "message": "TP/SL updated successfully", "result": { "market": "BTC", "tradeIndex": 0, "entryPrice": 95000.0, "takeProfitPrice": 123500.0, "stopLossPrice": 85500.0, "side": "long" } } ``` ### Avantis Trade History ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/history" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{ "venue": "AVANTIS", "userAddress": "0x...", "count": 50 }' ``` **Request Body:** ```json { "venue": "AVANTIS", // REQUIRED for Avantis via /history "userAddress": "0x...", // REQUIRED — the trader's wallet address "agentAddress": "0x...", // Alternative to userAddress "count": 50 // Optional — max results (default: 50) } ``` **Response:** ```json { "success": true, "venue": "AVANTIS", "source": "avantis_api_v2_history", "history": [ { "id": "69a6e3b7...", "tradeId": "1:0", "market": "BTC/USD", "pairIndex": 1, "tradeIndex": 0, "side": "long", "collateralUsdc": 9.955, "positionSizeUsdc": 1772.544045, "leverage": 10.0, "entryPrice": 67120.23805881, "closePrice": 67014.2049318, "usdcSentToTrader": 9.765164, "closedAt": "2026-03-03T13:35:51.000Z", "timestamp": 1709000000, "grossPnlUsdc": -0.144682 } ], "count": 4 } ``` ### Avantis Parameter Dependency Graph | Parameter | Source | How to Get | |-----------|--------|-----------| | `userAddress` | `/user-details` → `user_wallet` | `GET /user-details` | | `agentAddress` | `/user-details` → `ostium_agent_address` | `GET /user-details` | | `avantis_enabled` | `/user-details` → `deployment.enabled_venues` includes `AVANTIS` | `GET /user-details` | | `market` | User specifies token | User input (e.g. `BTC`, `ETH`) | | `side` | User specifies `"long"` or `"short"` | User input (required) | | `collateral` | User specifies USDC amount (must satisfy venue minimums) | User input (required) | | `leverage` | User specifies | User input | | `tradeId` | `/avantis/positions` → `tradeId` (`<pairIndex>:<tradeIndex>`) | Preferred unique open-trade key | | `tradeIndex` | `/avantis/positions` → `tradeIndex` | From position data | ### Avantis Workflow: Open Position on Base Chain ``` Step 1: GET /user-details → Extract: user_wallet, ostium_agent_address (shared agent wallet) → Check: deployment.enabled_venues includes AVANTIS (if not, tell user to enable Avantis at maxxit.ai/openclaw) Step 2: GET /avantis/symbols → Verify the token is available on Avantis Step 3: ASK the user for ALL trade parameters → "Which token?" (e.g. BTC, ETH) → "Long or short?" → "How much USDC collateral?" → "Leverage? (e.g. 10x)" → "Would you like to set TP/SL? If so, what percentages?" Step 4: POST /avantis/open-position → Use agentAddress and userAddress from Step 1 → Use market, side, collateral, leverage from Step 3 → SAVE: tradeIndex and entryPrice from response ``` ### Avantis Workflow: Close Position ``` Step 1: GET /user-details → Extract user_wallet, ostium_agent_address (shared agent wallet) Step 2: POST /avantis/positions (userAddress + agentAddress) → Show positions to user, let them pick which to close → Extract tradeIndex Step 3: POST /avantis/close-position → Pass agentAddress, userAddress, market → Optionally pass actualTradeIndex ``` --- ## Zerodha (Indian Stocks) Endpoints > Zerodha is an Indian stock broker supporting equities on NSE and BSE. Use Zerodha endpoints when the user wants to trade Indian stocks, mentions NSE/BSE, or says "Indian stocks", "equities", or "Zerodha". ### When to Use Zerodha - User wants to trade Indian stocks on NSE or BSE - User mentions "Indian stocks", "equities", "NSE", "BSE", "Zerodha", or "Kite" - User asks about their Zerodha portfolio, holdings, or positions - User wants to place, modify, or cancel orders on Indian exchanges - User wants to fetch instrument lists or market data for Indian equities ### Currency Convention - In Indian-market conversations, present prices, holdings, portfolio values, targets, and stop losses in **₹** - Prefer `₹` in normal user-facing replies - Do not default to USD when the context is Zerodha, NSE, BSE, or Indian equities ### TP/SL and GTT Guidance - When the user wants to set a take profit or stop loss for a Zerodha position, confirm whether they want to place a **GTT** order. - Explain GTT briefly when needed: **GTT (Good Till Triggered)** is a Zerodha trigger order that stays active until the trigger condition is hit or the user cancels it, and it is commonly used to automate target and stop-loss execution for cash-market positions. - If the user explicitly asks for GTT, use the Zerodha GTT flow directly. - If the user asks for TP/SL but does not mention GTT, ask first instead of assuming they want a regular order or a GTT trigger. ### Venue Routing | Keywords | Route | |----------|-------| | "Indian stocks", "NSE", "BSE", "equities", "Zerodha", "Kite" | Zerodha endpoints | ### Environment Variables | Variable | Description | Source | |----------|-------------|--------| | `KITE_API_KEY` | Zerodha Kite Connect API key | SSM (set in OpenClaw UI) | | `KITE_API_SECRET` | Zerodha Kite Connect API secret | SSM (set in OpenClaw UI) | | `KITE_ACCESS_TOKEN` | Short-lived access token (expires daily) | SSM (auto-stored after OAuth) | | `KITE_USER_NAME` | Zerodha display name for status/UI | SSM (auto-stored after OAuth) | ### Auth Pre-Flight Before any Zerodha trading call, check session validity: ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/session" \ -H "X-[REDACTED_SECRET]" \ -H "X-KITE-[REDACTED_SECRET]" \ -H "X-KITE-ACCESS-[REDACTED_SECRET]" ``` If `authenticated: false` or `expired: true`, tell the user: > "Your Zerodha session has expired. Please re-authenticate on the OpenClaw page at maxxit.ai/openclaw." **Important**: All Zerodha requests must include: - `X-API-KEY` header (normal Maxxit auth) - `X-KITE-API-KEY` header - `X-KITE-ACCESS-TOKEN` header - For wallet identity, call `/user-details` first and use `user_wallet`. Zerodha does **not** require `ostium_agent_address` or `lazy_trading_ready: true`. ### Zerodha Endpoints All base path: `${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/` #### GET /zerodha/login Generate a Zerodha login URL for the user. Important: - Do not tell the user to open a bare Kite URL like `https://kite.zerodha.com/connect/login?[REDACTED_SECRET]`. - The login flow must preserve the Maxxit user context so the callback can store the Zerodha session against the correct wallet. - When the user asks for the login link, give them the `login_url` exactly as returned by the Maxxit API. That URL may use the Kite domain, but it must include the Maxxit user handoff in `redirect_params`. - Preferred flow: 1. Call `GET /user-details` to resolve `user_wallet`. 2. Call `GET /zerodha/login` with `X-API-KEY`. 3. Send the returned `login_url` to the user. - Do **not** manually construct a `?userWallet=<wallet>&redirect=1` URL in the normal skill flow. - If you present the returned `login_url`, only use it if it includes the user handoff, e.g. `redirect_params=userWallet%3D...`. ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/login" \ -H "X-[REDACTED_SECRET]" ``` **Response:** ```json { "success": true, "login_url": "https://kite.zerodha.com/connect/login?[REDACTED_SECRET]", "message": "Open the login_url in your browser to authenticate with Zerodha." } ``` #### GET /zerodha/session Check Zerodha session status. Returns `authenticated: true` if session is valid. ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/session" \ -H "X-[REDACTED_SECRET]" \ -H "X-KITE-[REDACTED_SECRET]" \ -H "X-KITE-ACCESS-[REDACTED_SECRET]" ``` #### DELETE /zerodha/session Invalidate Zerodha session and remove token from SSM. #### GET /zerodha/portfolio Fetch portfolio data. Use `?type=profile|holdings|positions|margins` to select specific data. Default fetches all. ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/portfolio" \ -H "X-[REDACTED_SECRET]" \ -H "X-KITE-[REDACTED_SECRET]" \ -H "X-KITE-ACCESS-[REDACTED_SECRET]" ``` With filter: ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/portfolio?type=holdings" \ -H "X-[REDACTED_SECRET]" \ -H "X-KITE-[REDACTED_SECRET]" \ -H "X-KITE-ACCESS-[REDACTED_SECRET]" ``` #### GET /zerodha/orders List all orders. Use `?orderId=<id>` for specific order history. ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/orders" \ -H "X-[REDACTED_SECRET]" \ -H "X-KITE-[REDACTED_SECRET]" \ -H "X-KITE-ACCESS-[REDACTED_SECRET]" ``` #### POST /zerodha/orders Place a new order. ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/orders" \ -H "X-[REDACTED_SECRET]" \ -H "X-KITE-[REDACTED_SECRET]" \ -H "X-KITE-ACCESS-[REDACTED_SECRET]" \ -H 'Content-Type: application/json' \ -d '{ "variety": "regular", "exchange": "NSE", "tradingsymbol": "RELIANCE", "transaction_type": "BUY", "quantity": 1, "product": "CNC", "order_type": "MARKET" }' ``` **Required fields:** `exchange`, `tradingsymbol`, `transaction_type`, `quantity`, `product`, `order_type` **Common values:** | Field | Values | |-------|--------| | `variety` | `regular`, `amo`, `co`, `iceberg`, `auction` | | `exchange` | `NSE`, `BSE`, `NFO`, `BFO`, `CDS`, `MCX` | | `transaction_type` | `BUY`, `SELL` | | `product` | `CNC`, `NRML`, `MIS`, `MTF` | | `order_type` | `MARKET`, `LIMIT`, `SL`, `SL-M` | | `validity` | `DAY`, `IOC`, `TTL` | **How to explain Zerodha order fields to a normal trader:** | Field | Value | Meaning for a trader | |-------|-------|----------------------| | `variety` | `regular` | Standard exchange order placed during market hours. Use this by default unless the user asks for something more specific. | | `variety` | `amo` | After Market Order. Place the order outside market hours so it gets queued for the next session. | | `variety` | `co` | Cover Order. An intraday order paired with a compulsory stop loss. Use only if the user specifically wants a leveraged intraday order with a built-in risk stop. | | `variety` | `iceberg` | Iceberg Order. Splits one large order into smaller legs so the full size is not sent at once. Useful for quantities above freeze limits or to reduce visible impact. | | `variety` | `auction` | Auction Order. Used for exchange auction sessions, not for normal cash-market trading. Only use when the user explicitly wants auction participation. | | `order_type` | `MARKET` | Buy or sell immediately at the best available price. Prioritizes execution over exact price. | | `order_type` | `LIMIT` | Execute only at the specified price or better. Prioritizes price control over certainty of fill. | | `order_type` | `SL` | Stop-loss limit order. Once the trigger is hit, Zerodha places a limit order. Gives price control, but the order may remain unfilled in fast moves. | | `order_type` | `SL-M` | Stop-loss market order. Once the trigger is hit, Zerodha places a market order. Better for ensuring exit, but fill price can slip. | | `product` | `CNC` | Cash and Carry. Standard delivery equity order for shares you want to hold, typically in NSE/BSE cash markets. | | `product` | `NRML` | Normal order type commonly used for futures and options carry-forward positions, and other non-intraday derivatives exposure. | | `product` | `MIS` | Margin Intraday Squareoff. Intraday-only product, typically for futures/options or same-day cash trading where the position is not meant to be carried overnight. | | `product` | `MTF` | Margin Trading Facility. Broker-funded carry-forward equity position. Use only if the user explicitly asks for MTF and their account supports it. | | `validity` | `DAY` | Order stays active for the current trading session unless filled or cancelled. | | `validity` | `IOC` | Immediate or Cancel. Whatever can fill immediately will execute; the rest is cancelled right away. | | `validity` | `TTL` | Time to Live. The order stays active only for the specified number of minutes, using `validity_ttl`. | | `market_protection` | `0` | No market protection. Default behavior. | | `market_protection` | `0 - 100` | Custom market-protection percentage for market and stop-market style execution. Helps cap how far execution can chase price. Example: `2` means 2%. | | `market_protection` | `-1` | Automatic market protection chosen by the system based on Zerodha rules. | | `autoslice` | `true` | Automatically split a large order into multiple slices when quantity is above freeze limits. | | `autoslice` | `false` | Do not auto-slice. Default behavior. | **Extra order parameters supported by this route:** - `validity_ttl`: number of minutes when `validity` is `TTL` - `iceberg_legs`: number of child legs for an iceberg order - `iceberg_quantity`: quantity per iceberg leg - `auction_number`: required when placing auction orders - `market_protection`: market protection setting for eligible orders - `autoslice`: whether Zerodha should automatically slice oversized orders **Agent guidance:** - Default to `variety: regular`, `validity: DAY`, and either `MARKET` or `LIMIT` based on what the user asks. - Do not choose `CO`, `iceberg`, `auction`, `MTF`, `TTL`, `market_protection`, or `autoslice` unless the user explicitly wants that behavior or it is clearly necessary for the order they described. - If the user asks in plain English, translate the intent into these fields and explain the tradeoff briefly before placing the order. #### PUT /zerodha/orders?orderId=<id> Modify an existing order. ```bash curl -L -X PUT "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/orders?orderId=ORD123" \ -H "X-[REDACTED_SECRET]" \ -H "X-KITE-[REDACTED_SECRET]" \ -H "X-KITE-ACCESS-[REDACTED_SECRET]" \ -H 'Content-Type: application/json' \ -d '{"variety": "regular", "price": 2500, "order_type": "LIMIT"}' ``` #### DELETE /zerodha/orders?orderId=<id> Cancel an order. ```bash curl -L -X DELETE "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/orders?orderId=ORD123" \ -H "X-[REDACTED_SECRET]" \ -H "X-KITE-[REDACTED_SECRET]" \ -H "X-KITE-ACCESS-[REDACTED_SECRET]" \ -H 'Content-Type: application/json' \ -d '{"variety": "regular"}' ``` #### GET /zerodha/gtt List all GTT triggers. Use `?triggerId=<id>` to fetch a specific trigger. ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/gtt" \ -H "X-[REDACTED_SECRET]" \ -H "X-KITE-[REDACTED_SECRET]" \ -H "X-KITE-ACCESS-[REDACTED_SECRET]" ``` #### POST /zerodha/gtt Place a new GTT trigger. ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/gtt" \ -H "X-[REDACTED_SECRET]" \ -H "X-KITE-[REDACTED_SECRET]" \ -H "X-KITE-ACCESS-[REDACTED_SECRET]" \ -H 'Content-Type: application/json' \ -d '{ "trigger_type": "two-leg", "tradingsymbol": "SBIN", "exchange": "NSE", "trigger_values": [800, 840], "last_price": 835, "orders": [ { "transaction_type": "SELL", "quantity": 1, "product": "CNC", "order_type": "LIMIT", "price": 840 }, { "transaction_type": "SELL", "quantity": 1, "product": "CNC", "order_type": "LIMIT", "price": 800 } ] }' ``` **Required fields:** `trigger_type`, `tradingsymbol`, `exchange`, `trigger_values`, `last_price`, `orders` **Rules:** - `trigger_type: "single"` requires exactly 1 `trigger_values` item and 1 order - `trigger_type: "two-leg"` requires exactly 2 `trigger_values` items and 2 orders #### PUT /zerodha/gtt?triggerId=<id> Modify an existing GTT trigger. ```bash curl -L -X PUT "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/gtt?triggerId=219118727" \ -H "X-[REDACTED_SECRET]" \ -H "X-KITE-[REDACTED_SECRET]" \ -H "X-KITE-ACCESS-[REDACTED_SECRET]" \ -H 'Content-Type: application/json' \ -d '{ "trigger_type": "two-leg", "tradingsymbol": "SBIN", "exchange": "NSE", "trigger_values": [800, 860], "last_price": 837, "orders": [ { "transaction_type": "SELL", "quantity": 1, "product": "CNC", "order_type": "LIMIT", "price": 860 }, { "transaction_type": "SELL", "quantity": 1, "product": "CNC", "order_type": "LIMIT", "price": 800 } ] }' ``` #### DELETE /zerodha/gtt?triggerId=<id> Delete an existing GTT trigger. ```bash curl -L -X DELETE "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/gtt?triggerId=219118727" \ -H "X-[REDACTED_SECRET]" \ -H "X-KITE-[REDACTED_SECRET]" \ -H "X-KITE-ACCESS-[REDACTED_SECRET]" ``` #### GET /zerodha/instruments Fetch available instruments. Use `?exchange=NSE|BSE|NFO|BFO|CDS|MCX` to filter. ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/zerodha/instruments?exchange=NSE" \ -H "X-[REDACTED_SECRET]" \ -H "X-KITE-[REDACTED_SECRET]" \ -H "X-KITE-ACCESS-[REDACTED_SECRET]" ``` ### Zerodha Workflow: Trading Indian Stocks ``` Step 1: GET /zerodha/session → Check if authenticated. If not → tell user to re-auth on OpenClaw page. Step 2: GET /user-details → Extract: user_wallet → Ignore lazy_trading_ready / ostium_agent_address for Zerodha flows Step 3: GET /zerodha/instruments?exchange=NSE → Verify the symbol exists on the exchange. Step 4: GET /zerodha/portfolio?type=holdings → Show current holdings and positions to user. Step 5: ASK user for trade parameters → Exchange (NSE/BSE), symbol, BUY/SELL, quantity, product (CNC/MIS), order type Step 6: POST /zerodha/orders → Place the order with confirmed parameters. Step 7: GET /zerodha/orders?orderId=<id> → Verify order status. ``` ### Zerodha Error Handling | Status | Meaning | |--------|---------| | 401 | Session expired. Tell user to re-authenticate. | | 400 | Missing or invalid parameters. | | 405 | Wrong HTTP method. | | 500 | Internal error or Zerodha API failure. | --- Trustless ZK-verified trading signals. **Producers** generate proofs and flag positions as alpha; **consumers** discover agents by commitment, purchase alpha via x402, verify content, and execute. **Base path:** `${MAXXIT_API_URL}/api/lazy-trading/programmatic/alpha/*` **Auth:** `X-API-KEY` header (same as other endpoints). **Payment:** On-chain USDC on Arbitrum Sepolia (testnet) or Arbitrum One (mainnet). **Prerequisites for consuming alpha:** - User must have completed Lazy Trading setup (agent deployed) — `/user-details` must return `ostium_agent_address`. The `/pay` endpoint uses this agent to send USDC; without it, `/pay` returns 400. - Agent wallet must hold enough USDC for the listing price. If insufficient, `/pay` returns 402 with `required` and `available` amounts — inform the user to fund the agent address. ### Alpha Endpoints Summary | Endpoint | Method | Purpose | |----------|--------|---------| | `/alpha/agents` | GET | Discover agents with verified metrics (commitment, winRate, totalPnl). Query: `minWinRate`, `minTrades`, `limit`. | | `/alpha/listings` | GET | Browse active alpha listings (metadata + price, no trade content). Query: `commitment`, `maxPrice`, `limit`. | | `/alpha/purchase/:listingId` | GET | **Phase 1** (no `X-Payment` header): returns 402 + payment details. **Phase 2** (with `X-Payment: txHash`): verifies on-chain, returns alpha. | | `/alpha/pay/:listingId` | POST | **Payment helper**: sends USDC from your agent on-chain. Returns `txHash`. Call between Phase 1 and Phase 2. | | `/alpha/verify` | POST | Body: `{ listingId, content }`. Verify purchased content hash matches commitment. | | `/alpha/execute` | POST | Body: `{ alphaContent, agentAddress, userAddress, collateral, leverageOverride? }`. Execute alpha trade on the venue from `alphaContent.venue` (`OSTIUM` or `AVANTIS`). | | `/alpha/0g-decision` | POST | Sponsored 0G Compute trade decision. Body: `{ deploymentId, tokenSymbol, marketResearchSummary }`. Returns `{ shouldTrade, side, confidence, reasoning, modelUsed, sponsored }`. | | `/alpha/generate-proof` | POST | (Producer) Generate ZK proof of trading performance. Body: `{ venue?: \"OSTIUM\" | \"AVANTIS\", tradeId?: string, autoProcess?: boolean }`. Pass `tradeId` to feature a specific trade; omit for most recent open trade. `autoProcess: false` is processed by the worker (~3-5 min). | | `/alpha/proof-status` | GET | (Producer) Check proof processing status. Query: `proofId`. | | `/alpha/my-proof` | GET | (Producer) Latest proof status and metrics. | | `/alpha/flag` | POST | (Producer) Body: `{ proofId, priceUsdc, token, side, leverage? }`. List verified trade as alpha using the proof ID from generate-proof. Response may include `ogStorage.rootHash` and `ogStorage.txHash` when 0G storage succeeds. | **Venue/trade reference notes:** - `tradeId` for `venue: "OSTIUM"` should be the trade index (example: `"123"`). - For `venue: "AVANTIS"`, use tradeId from `/avantis/positions`: `"<pairIndex>:<tradeIndex>"` (example: `"1:0"`). - Internally, proofs/listings are stored as a prefixed trade reference: `<VENUE>:<ID>` (for example, `OSTIUM:123`, `AVANTIS:1:0`). ### How x402 Purchase Works (3 API Calls) > **⚠️ CRITICAL**: To purchase alpha content you MUST call these 3 endpoints in this exact order. Do NOT skip steps. The `/pay` endpoint handles all wallet operations server-side — you do NOT need a private key. ``` Step A: GET /alpha/purchase/{listingId} → 402 + paymentDetails Step B: POST /alpha/pay/{listingId} → { txHash } Step C: GET /alpha/purchase/{listingId} → 200 + alpha content + Header: X-Payment: {txHash from Step B} ``` **Step A — Get payment details:** ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/alpha/purchase/{listingId}" \ -H "X-[REDACTED_SECRET]" ``` Response: `402` with `paymentDetails.price`, `paymentDetails.payTo`, `paymentDetails.network`. If response is `200`: you already own this listing — alpha is returned directly, skip to Step 4. **Step B — Send USDC (server handles everything):** ```bash curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/alpha/pay/{listingId}" \ -H "X-[REDACTED_SECRET]" ``` Response: `200` with `txHash`, `from`, `to`, `amount`. If `alreadyPaid: true`: use the returned `txHash` directly. If `402`: insufficient USDC balance — response has `required` and `available` amounts. **Step C — Retrieve alpha content:** ```bash curl -L -X GET "${MAXXIT_API_URL}/api/lazy-trading/programmatic/alpha/purchase/{listingId}" \ -H "X-[REDACTED_SECRET]" \ -H "X-Payment: {txHash from Step B}" ``` Response: `200` with `alpha` object (token, side, leverage, venue, entryPrice), `contentHash`, `payment` receipt. **SAVE from Step C:** `alpha`, `contentHash`, `listingId` — needed for `/verify` and `/execute`. **Pass `content` exactly as received:** For `/alpha/verify`, the `content` field must be the exact `alpha` object from Step C. Do not modify keys, values, or key order — the hash is computed using sorted keys and any change will cause verification to fail. ### Alpha Dependency Chain ``` /alpha/agents → commitment /alpha/listings → listingId (needs commitment) /alpha/purchase → 402 paymentDetails (needs listingId) /alpha/pay → txHash (needs listingId) /alpha/purchase → alpha content (needs listingId + txHash in X-Payment header) /alpha/verify → verified (needs listingId + alpha content) /user-details → agentAddress, userAddress /alpha/execute → trade result (needs alpha + addresses + collateral) ``` ### Workflow: Consuming Alpha (Complete Flow) ``` Step 1: GET /alpha/agents → Pick an agent by commitment, winRate, totalPnl → SAVE: commitment Step 2: GET /alpha/listings?commitment={commitment} → Browse listings, pick one → SAVE: listingId Step 3a: GET /alpha/purchase/{listingId} → If 200: already purchased, skip to Step 4 → If 402: need to pay → go to Step 3b Step 3b: POST /alpha/pay/{listingId} → Server sends USDC from your agent to the producer → If 402: insufficient USDC balance → fund your agent wallet and retry → If alreadyPaid: use the returned txHash → SAVE: txHash Step 3c: GET /alpha/purchase/{listingId} → Header: X-Payment: {txHash from Step 3b} → SAVE: alpha, contentHash, listingId Step 4: POST /alpha/verify → Body: { "listingId": "...", "content": { ...alpha from Step 3c } } → Check: verified === true Step 5: GET /user-details → Extract: user_wallet → userAddress → Extract: ostium_agent_address → agentAddress Step 6: POST /alpha/execute → Body: { "alphaContent": { ...alpha }, "agentAddress": "...", "userAddress": "...", "collateral": 100 } → alphaContent must include at least token and side (from alpha) → agentAddress = ostium_agent_address, userAddress = user_wallet (both from /user-details) → collateral: ask user or use default (e.g. 100 USDC) → Check: success === true ``` ### Workflow: Producing Alpha > **⚠️ This is the standalone producer workflow.** If the user just opened a position via Workflow 1, Steps 7-10 already handle alpha listing — you don't need to repeat this. Use this workflow only when the user wants to list an existing open position. ``` Step 1: POST /positions (address = user_wallet from /user-details) → List open positions → Let user pick which trade to feature → SAVE: tradeId, market (token), side, leverage from the chosen position Step 2: POST /alpha/generate-proof → Body: { "venue": "OSTIUM", "tradeId": "{tradeId from Step 1}", "autoProcess": true } → SAVE: proofId from response → If status is already VERIFIED → go to Step 4 Step 3: Poll GET /alpha/proof-status?proofId={proofId} → Wait until status === "VERIFIED" → Poll every 10 seconds (max ~5 min) → If FAILED → inform user and stop Step 4: ASK user for price → "What USDC price would you like to charge for this alpha?" Step 5: POST /alpha/flag → Body: { "proofId": "{proofId from Step 2}", "priceUsdc": {price from Step 4}, "token": "{market from Step 1}", "side": "{side from Step 1}", "leverage": {leverage from Step 1} } → Show user: listingId, proofMetrics (tradeCount, winRate, totalPnl) → If ogStorage.rootHash is present, show: "Your trade is listed as alpha! Listing ID : {listingId} 0G Storage Root: {ogStorage.rootHash}" → If ogStorage.rootHash is null, show: "Your trade is listed as alpha in the Maxxit DB. 0G storage was unavailable." ``` **Example curl commands:** ```bash # Generate proof with specific tradeId curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/alpha/generate-proof" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{"venue":"OSTIUM","tradeId":"1612509","autoProcess":false}' # Check proof status curl -G "${MAXXIT_API_URL}/api/lazy-trading/programmatic/alpha/proof-status" \ -H "X-[REDACTED_SECRET]" \ --data-urlencode "proofId=<proof_id>" # Flag as alpha using proofId curl -L -X POST "${MAXXIT_API_URL}/api/lazy-trading/programmatic/alpha/flag" \ -H "X-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d '{"proofId": "<proof_id>", "priceUsdc": 5, "token": "ETH", "side": "long", "leverage": 6}' ``` --- ## Environment Variables | Variable | Description | Example | |----------|-------------|---------| | `MAXXIT_API_KEY` | Your lazy trading API key (starts with `lt_`) | `lt_abc123...` | | `MAXXIT_API_URL` | Maxxit API base URL | `https://maxxit.ai` | ## Error Handling | Status Code | Meaning | |-------------|---------| | 401 | Invalid or missing API key | | 404 | Resource not found for the specific endpoint (not returned by `/user-details` just because an agent is missing) | | 400 | Missing or invalid message / parameters | | 405 | Wrong HTTP method | | 500 | Server error | **Alpha-specific errors:** | 400 | `/pay`: No agent address found (user must complete Lazy Trading setup). `/purchase`: Invalid X-Payment header or payment verification failed. | | 402 | Payment required (`/purchase` Phase 1) or insufficient USDC balance (`/pay` — check `required` and `available` in response). | | 409 | Transaction hash already used (replay protection — each tx can only purchase one listing). | | 410 | Alpha listing no longer active. | ## Getting Started 1. **Set up Lazy Trading**: Visit https://maxxit.ai/lazy-trading to connect your wallet and configure your agent 2. **Generate API Key**: Go to your dashboard and create an API key 3. **Configure Environment**: Set `MAXXIT_API_KEY` and `MAXXIT_API_URL` 4. **Start Trading**: Use this skill to send signals! ## Security Notes - Never share your API key - API keys can be revoked and regenerated from the dashboard - All trades execute on-chain with your delegated wallet permissions

path: taker-strategy.py
content: #!/usr/bin/env python3
"""Aggressive Taker (Order Flow) bot for Maxxit Lazy Trading.
Uses Binance Taker Buy/Sell volume as a leading indicator for HFT scalping.
"""
import json
import logging
import math
import os
import sys
from datetime import datetime
from typing import Any, Dict, List, Optional

import argparse

# Configuration
BASE_DIR = os.getcwd()
LOG_DIR = os.path.join(BASE_DIR, "logs")
MAXXIT_API_URL = os.environ.get("MAXXIT_API_URL")
MAXXIT_API_KEY = os.environ.get("MAXXIT_API_KEY")

def parse_args():
    parser = argparse.ArgumentParser(description="Aggressive Taker Strategy Bot")
    parser.add_argument("--symbol", required=True, help="Trading symbol (e.g., BTC/USD)")
    parser.add_argument("--venue", required=True, choices=["OSTIUM", "AVANTIS"], help="Trading venue (OSTIUM or AVANTIS)")
    parser.add_argument("--leverage", type=int, default=10, help="Leverage to use")
    parser.add_argument("--utilization", type=float, default=0.8, help="Collateral utilization ratio")
    return parser.parse_args()

args = parse_args()

# Global Parameters from Args
SYMBOL = args.symbol
MARKET = SYMBOL.split('/')[0]
VENUE = args.venue.upper()
COLLATERAL_UTILIZATION = args.utilization
LEVERAGE = args.leverage
TAKER_RATIO_THRESHOLD = float(os.environ.get("TAKER_RATIO_THRESHOLD", "0.60"))
MIN_COLLATERAL = 1.0

STATE_FILE = os.path.join(BASE_DIR, f"{VENUE.lower()}_{MARKET.lower()}_taker_state.json")
LOG_FILE = os.path.join(LOG_DIR, f"{VENUE.lower()}_{MARKET.lower()}_taker.log")

def log(message: str) -> None:
    logging.info(message)
    print(f"{datetime.utcnow().isoformat()} - {message}")

def ensure_environment() -> None:
    if not MAXXIT_API_URL or not MAXXIT_API_KEY:
        raise EnvironmentError("MAXXIT_API_URL and MAXXIT_API_KEY must be set")
    os.makedirs(LOG_DIR, exist_ok=True)
    if not logging.getLogger().handlers:
        logging.basicConfig(
            filename=LOG_FILE,
            level=logging.INFO,
            format="%(asctime)s %(levelname)s %(message)s",
            datefmt="%Y-%m-%d %H:%M:%S",
        )

def load_state() -> Dict[str, Any]:
    if not os.path.isfile(STATE_FILE):
        return {"last_direction": None, "last_ratio": None}
    try:
        with open(STATE_FILE, "r") as f:
            return json.load(f)
    except (ValueError, IOError):
        return {"last_direction": None, "last_ratio": None}

def save_state(state: Dict[str, Any]) -> None:
    with open(STATE_FILE, "w") as f:
        json.dump(state, f)

def api_get(session: requests.Session, path: str, params: Optional[Dict[str, Any]] = None) -> Optional[Dict[str, Any]]:
    url = f"{MAXXIT_API_URL}/api/lazy-trading/programmatic/{path}"
    try:
        response = session.get(url, params=params, timeout=30)
        response.raise_for_status()
        return response.json()
    except requests.RequestException as exc:
        log(f"GET {path} failed: {exc}")
        return None

def api_post(session: requests.Session, path: str, payload: Dict[str, Any]) -> Optional[Dict[str, Any]]:
    url = f"{MAXXIT_API_URL}/api/lazy-trading/programmatic/{path}"
    try:
        response = session.post(url, json=payload, timeout=30)
        response.raise_for_status()
        return response.json()
    except requests.RequestException as exc:
        log(f"POST {path} failed: {exc}")
        return None

def fetch_binance_klines(market: str, interval: str = "5m", limit: int = 5) -> List[Dict[str, float]]:
    """Fetches klines and extracts Taker Volume data."""
    symbol = f"{market}USDT"
    url = "https://api.binance.com/api/v3/klines"
    params = {"symbol": symbol, "interval": interval, "limit": limit}
    try:
        resp = requests.get(url, params=params, timeout=10)
        resp.raise_for_status()
        data = resp.json()
        # [OpenTime, Open, High, Low, Close, Vol, CloseTime, QuoteVol, Trades, TakerBuyBase, TakerBuyQuote, Ignore]
        return [
            {
                "close": float(item[4]),
                "volume": float(item[5]),
                "taker_buy_volume": float(item[9])
            }
            for item in data
        ]
    except Exception as exc:
        log(f"Failed to fetch Binance klines: {exc}")
        return []

def determine_signal(klines: List[Dict[str, float]]) -> Optional[str]:
    if not klines:
        return None
    
    # Calculate average taker ratio over the last few candles
    total_vol = sum(k['volume'] for k in klines)
    total_taker_buy = sum(k['taker_buy_volume'] for k in klines)
    
    if total_vol == 0:
        return None
        
    ratio = total_taker_buy / total_vol
    log(f"Taker Buy Ratio: {ratio:.4f}")
    
    if ratio > TAKER_RATIO_THRESHOLD:
        return "long"
    elif ratio < (1 - TAKER_RATIO_THRESHOLD):
        return "short"
    return None

def main() -> None:
    ensure_environment()
    session = requests.Session()
    session.headers.update({"X-API-KEY": MAXXIT_API_KEY, "Content-Type": "application/json"})
    
    state = load_state()
    log(f"Starting Aggressive Taker Bot | Market: {MARKET} | Venue: {VENUE}")

    # 1. Get Club Details
    club = api_get(session, "user-details")
    if not club:
        return
    user_address = club.get("user_wallet")
    agent_address = club.get("ostium_agent_address")
    
    # 2. Fetch Order Flow Data
    klines = fetch_binance_klines(MARKET)
    signal = determine_signal(klines)
    
    if signal is None:
        log("No strong order flow signal detected; skipping.")
        return

    # 3. Get Account Balance (Venue Specific)
    balance_path = f"{VENUE.lower()}/balance" if VENUE == "AVANTIS" else "balance"
    balance_payload = {"userAddress": user_address} if VENUE == "AVANTIS" else {"address": user_address}
    
    balance = api_post(session, balance_path, balance_payload)
    if not balance:
        return
    usdc_balance = float(balance.get("usdcBalance", 0))
    
    # 4. Check for Existing Position
    pos_path = f"{VENUE.lower()}/positions" if VENUE == "AVANTIS" else "positions"
    pos_payload = {"userAddress": user_address, "agentAddress": agent_address} if VENUE == "AVANTIS" else {"address": user_address}
    
    positions_resp = api_post(session, pos_path, pos_payload)
    existing_position = None
    if positions_resp and positions_resp.get("positions"):
        for pos in positions_resp["positions"]:
            if pos.get("market") == MARKET or pos.get("marketFull") == SYMBOL:
                existing_position = pos
                break

    # 5. Execute Logic
    if existing_position:
        existing_side = existing_position.get("side", "").lower()
        if existing_side == signal:
            log(f"Already in a {signal} position. No action needed.")
            return
        else:
            # Flip Position: Close old one
            log(f"Signal flipped to {signal}. Closing existing {existing_side} position.")
            close_path = f"{VENUE.lower()}/close-position" if VENUE == "AVANTIS" else "close-position"
            close_payload = {
                "agentAddress": agent_address,
                "userAddress": user_address,
                "market": MARKET,
                "actualTradeIndex": existing_position.get("tradeIndex")
            }
            api_post(session, close_path, close_payload)

    # Calculate collateral
    collateral = min(usdc_balance * COLLATERAL_UTILIZATION, usdc_balance)
    if collateral < MIN_COLLATERAL:
        log("Insufficient balance to open position.")
        return

    # Open Position
    open_path = f"{VENUE.lower()}/open-position" if VENUE == "AVANTIS" else "open-position"
    open_payload = {
        "agentAddress": agent_address,
        "userAddress": user_address,
        "market": MARKET,
        "side": signal,
        "collateral": round(collateral, 2),
        "leverage": LEVERAGE,
        "takeProfitPercent": 0.02, # 2% TP for scalping
        "stopLossPercent": 0.01    # 1% SL for scalping
    }
    
    open_resp = api_post(session, open_path, open_payload)
    if open_resp and open_resp.get("success"):
        log(f"Opened {signal} position on {VENUE} for {MARKET}")
    
    state["last_direction"] = signal
    save_state(state)

if __name__ == "__main__":
    main()


path: rsi-bollinger-strategy.py
content: #!/usr/bin/env python3
"""RSI + Bollinger mean reversion strategy for Maxxit lazy trading."""

import argparse
from typing import Any, Dict, List, Optional

from strategy_common import (
    VALID_INTERVALS,
    VALID_VENUES,
    bollinger_bands,
    build_config,
    closes,
    create_session,
    ensure_environment,
    execute_signal,
    fetch_binance_klines,
    load_state,
    log,
    rsi,
    save_state,
)


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="RSI + Bollinger mean reversion strategy. Fades band extremes and enters on re-entry confirmation."
    )
    parser.add_argument("--symbol", type=str, default="BTCUSDT", help="Binance trading pair symbol. Default: BTCUSDT")
    parser.add_argument("--interval", type=str, default="5m", choices=VALID_INTERVALS, help="Candle interval. Default: 5m")
    parser.add_argument("--candles", type=int, default=80, help="Number of candles to fetch. Default: 80")
    parser.add_argument("--venue", type=str, default="avantis", choices=VALID_VENUES, help="DEX to trade on. Default: avantis")
    parser.add_argument("--rsi-period", type=int, default=14, help="RSI period. Default: 14")
    parser.add_argument("--bb-period", type=int, default=20, help="Bollinger lookback period. Default: 20")
    parser.add_argument("--bb-std", type=float, default=2.0, help="Bollinger standard deviation multiplier. Default: 2.0")
    parser.add_argument("--oversold-exit", type=float, default=35.0, help="Long re-entry RSI ceiling. Default: 35")
    parser.add_argument("--overbought-exit", type=float, default=65.0, help="Short re-entry RSI floor. Default: 65")
    parser.add_argument("--take-profit", type=float, default=0.02, help="Take profit percent. Default: 0.02")
    parser.add_argument("--stop-loss", type=float, default=0.012, help="Stop loss percent. Default: 0.012")
    args = parser.parse_args()
    minimum = max(args.rsi_period + 3, args.bb_period + 3)
    if args.candles < minimum:
        parser.error(f"candles must be >= {minimum} for the selected periods")
    return args


def determine_signal(
    candle_data: List[Dict[str, float]],
    rsi_values: List[Optional[float]],
    upper_band: List[Optional[float]],
    lower_band: List[Optional[float]],
    oversold_exit: float,
    overbought_exit: float,
) -> Optional[str]:
    if len(candle_data) < 3:
        return None

    prev_close = candle_data[-2]["close"]
    current_close = candle_data[-1]["close"]
    prev_upper = upper_band[-2]
    current_upper = upper_band[-1]
    prev_lower = lower_band[-2]
    current_lower = lower_band[-1]
    prev_rsi = rsi_values[-2]
    current_rsi = rsi_values[-1]

    if None in (prev_upper, current_upper, prev_lower, current_lower, prev_rsi, current_rsi):
        return None

    long_reentry = (
        prev_close < prev_lower
        and current_close > current_lower
        and current_rsi > prev_rsi
        and current_rsi <= oversold_exit
    )
    short_reentry = (
        prev_close > prev_upper
        and current_close < current_upper
        and current_rsi < prev_rsi
        and current_rsi >= overbought_exit
    )

    if long_reentry:
        return "long"
    if short_reentry:
        return "short"
    return None


def main() -> None:
    args = parse_args()
    config = build_config(
        symbol=args.symbol,
        interval=args.interval,
        candles=args.candles,
        venue=args.venue,
        strategy_slug="rsi_bollinger",
    )
    ensure_environment(config)
    state = load_state(config["state_file"])
    candles = fetch_binance_klines(config["binance_symbol"], config["interval"], config["num_candles"])
    close_values = closes(candles)
    rsi_values = rsi(close_values, args.rsi_period)
    upper_band, middle_band, lower_band = bollinger_bands(close_values, args.bb_period, args.bb_std)
    signal = determine_signal(
        candles,
        rsi_values,
        upper_band,
        lower_band,
        args.oversold_exit,
        args.overbought_exit,
    )

    latest_close = close_values[-1]
    latest_rsi = rsi_values[-1]
    latest_mid = middle_band[-1]
    log(
        f"RSI/Bollinger snapshot | close: {latest_close:.4f}, "
        f"rsi: {latest_rsi if latest_rsi is not None else 'n/a'}, "
        f"mid: {latest_mid if latest_mid is not None else 'n/a'}"
    )

    if signal is None:
        log("No RSI + Bollinger re-entry signal detected; skipping this run")
        state["last_close"] = latest_close
        state["last_rsi"] = latest_rsi
        state["last_signal"] = None
        save_state(state, config["state_file"])
        return

    session = create_session()
    success = execute_signal(
        session=session,
        config=config,
        signal=signal,
        reference_price=latest_close,
        take_profit=args.take_profit,
        stop_loss=args.stop_loss,
    )
    state["last_close"] = latest_close
    state["last_rsi"] = latest_rsi
    state["last_signal"] = signal if success else "failed"
    save_state(state, config["state_file"])


if __name__ == "__main__":
    main()


path: ema-strategy.py
content: #!/usr/bin/env python3
"""EMA crossover bot for trading on Ostium, Aster, or Avantis."""

import argparse
from typing import Any, Dict, List, Optional

from strategy_common import (
    VALID_INTERVALS,
    VALID_VENUES,
    build_config,
    closes,
    create_session,
    ema,
    ensure_environment,
    execute_signal,
    fetch_binance_klines,
    load_state,
    log,
    save_state,
)


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="EMA crossover strategy. Pass token symbol, candle interval, candle count, and fast/slow EMA periods."
    )
    parser.add_argument(
        "--symbol",
        type=str,
        default="BTCUSDT",
        help="Binance trading pair symbol (e.g. BTCUSDT, ETHUSDT). Default: BTCUSDT",
    )
    parser.add_argument(
        "--interval",
        type=str,
        default="5m",
        choices=VALID_INTERVALS,
        help="Candle interval. Default: 5m",
    )
    parser.add_argument(
        "--candles",
        type=int,
        default=40,
        help="Number of candles to fetch and use for EMA calculation. Must be >= slow_period + 2. Default: 40",
    )
    parser.add_argument(
        "--fast",
        type=int,
        default=5,
        dest="fast_period",
        help="Fast EMA period. Default: 5",
    )
    parser.add_argument(
        "--slow",
        type=int,
        default=20,
        dest="slow_period",
        help="Slow EMA period. Default: 20",
    )
    parser.add_argument(
        "--venue",
        type=str,
        default="avantis",
        choices=VALID_VENUES,
        help="DEX to trade on: ostium (Arbitrum), aster (BNB Chain), avantis (Base). Default: avantis",
    )
    parser.add_argument(
        "--take-profit",
        type=float,
        default=0.025,
        help="Take profit percent. Default: 0.025",
    )
    parser.add_argument(
        "--stop-loss",
        type=float,
        default=0.015,
        help="Stop loss percent. Default: 0.015",
    )
    args = parser.parse_args()
    if args.candles < args.slow_period + 2:
        parser.error(f"candles must be >= slow_period + 2 (got candles={args.candles}, slow_period={args.slow_period})")
    if args.fast_period >= args.slow_period:
        parser.error("fast_period must be less than slow_period")
    return args


def determine_signal(fast_values: List[Optional[float]], slow_values: List[Optional[float]]) -> Optional[str]:
    if len(fast_values) < 2 or len(slow_values) < 2:
        return None
    previous_fast = fast_values[-2]
    current_fast = fast_values[-1]
    previous_slow = slow_values[-2]
    current_slow = slow_values[-1]
    if None in (previous_fast, current_fast, previous_slow, current_slow):
        return None
    if previous_fast <= previous_slow and current_fast > current_slow:
        return "long"
    if previous_fast >= previous_slow and current_fast < current_slow:
        return "short"
    return None


def main() -> None:
    args = parse_args()
    config = build_config(
        symbol=args.symbol,
        interval=args.interval,
        candles=args.candles,
        venue=args.venue,
        strategy_slug="ema",
    )
    config["fast_period"] = args.fast_period
    config["slow_period"] = args.slow_period

    ensure_environment(config)
    state = load_state(config["state_file"])
    candles = fetch_binance_klines(config["binance_symbol"], config["interval"], config["num_candles"])
    price_values = closes(candles)
    fast_ema = ema(price_values, args.fast_period)
    slow_ema = ema(price_values, args.slow_period)
    signal = determine_signal(fast_ema, slow_ema)

    latest_price = price_values[-1]
    log(
        f"EMA snapshot | close: {latest_price:.4f}, "
        f"fast_ema: {fast_ema[-1] if fast_ema[-1] is not None else 'n/a'}, "
        f"slow_ema: {slow_ema[-1] if slow_ema[-1] is not None else 'n/a'}"
    )

    if signal is None:
        log("No EMA crossover signal detected; skipping this run")
        state["last_fast"] = fast_ema[-1]
        state["last_slow"] = slow_ema[-1]
        state["last_direction"] = None
        save_state(state, config["state_file"])
        return

    session = create_session()
    success = execute_signal(
        session=session,
        config=config,
        signal=signal,
        reference_price=latest_price,
        take_profit=args.take_profit,
        stop_loss=args.stop_loss,
    )
    state["last_fast"] = fast_ema[-1]
    state["last_slow"] = slow_ema[-1]
    state["last_direction"] = signal if success else "failed"
    save_state(state, config["state_file"])


if __name__ == "__main__":
    main()


path: mean-reversion-strategy.py
content: #!/usr/bin/env python3
"""Mean Reversion (RSI + Bollinger Bands) bot for Maxxit Lazy Trading.
Identifies oversold/overbought conditions in ranging markets for quick scalping.
"""
import json
import logging
import math
import os
import sys
from datetime import datetime
from typing import Any, Dict, List, Optional

import argparse

# Configuration
BASE_DIR = os.getcwd()
LOG_DIR = os.path.join(BASE_DIR, "logs")
MAXXIT_API_URL = os.environ.get("MAXXIT_API_URL")
MAXXIT_API_KEY = os.environ.get("MAXXIT_API_KEY")

def parse_args():
    parser = argparse.ArgumentParser(description="Mean Reversion Strategy Bot")
    parser.add_argument("--symbol", required=True, help="Trading symbol (e.g., BTC/USD)")
    parser.add_argument("--venue", required=True, choices=["OSTIUM", "AVANTIS"], help="Trading venue (OSTIUM or AVANTIS)")
    parser.add_argument("--leverage", type=int, default=10, help="Leverage to use")
    parser.add_argument("--utilization", type=float, default=0.8, help="Collateral utilization ratio")
    return parser.parse_args()

args = parse_args()

# Global Parameters from Args
SYMBOL = args.symbol
MARKET = SYMBOL.split('/')[0]
VENUE = args.venue.upper()
COLLATERAL_UTILIZATION = args.utilization
LEVERAGE = args.leverage

# Strategy Parameters
RSI_PERIOD = 7
RSI_OVERBOUGHT = 70
RSI_OVERSOLD = 30
BB_PERIOD = 20
BB_STD = 2.0

STATE_FILE = os.path.join(BASE_DIR, f"{VENUE.lower()}_{MARKET.lower()}_mean_state.json")
LOG_FILE = os.path.join(LOG_DIR, f"{VENUE.lower()}_{MARKET.lower()}_mean.log")

def log(message: str) -> None:
    logging.info(message)
    print(f"{datetime.utcnow().isoformat()} - {message}")

def ensure_environment() -> None:
    if not MAXXIT_API_URL or not MAXXIT_API_KEY:
        raise EnvironmentError("MAXXIT_API_URL and MAXXIT_API_KEY must be set")
    os.makedirs(LOG_DIR, exist_ok=True)
    if not logging.getLogger().handlers:
        logging.basicConfig(
            filename=LOG_FILE,
            level=logging.INFO,
            format="%(asctime)s %(levelname)s %(message)s",
            datefmt="%Y-%m-%d %H:%M:%S",
        )

def api_post(session: requests.Session, path: str, payload: Dict[str, Any]) -> Optional[Dict[str, Any]]:
    url = f"{MAXXIT_API_URL}/api/lazy-trading/programmatic/{path}"
    try:
        response = session.post(url, json=payload, timeout=30)
        response.raise_for_status()
        return response.json()
    except requests.RequestException as exc:
        log(f"POST {path} failed: {exc}")
        return None

def fetch_binance_klines(market: str, interval: str = "5m", limit: int = 50) -> List[float]:
    symbol = f"{market}USDT"
    url = "https://api.binance.com/api/v3/klines"
    params = {"symbol": symbol, "interval": interval, "limit": limit}
    try:
        resp = requests.get(url, params=params, timeout=10)
        resp.raise_for_status()
        return [float(item[4]) for item in resp.json()] # Just close prices
    except Exception as exc:
        log(f"Failed to fetch Binance klines: {exc}")
        return []

def calculate_rsi(prices: List[float], period: int = 14) -> Optional[float]:
    if len(prices) < period + 1:
        return None
    deltas = [prices[i+1] - prices[i] for i in range(len(prices)-1)]
    gain = [d if d > 0 else 0 for d in deltas]
    loss = [-d if d < 0 else 0 for d in deltas]
    
    avg_gain = sum(gain[:period]) / period
    avg_loss = sum(loss[:period]) / period
    
    for i in range(period, len(deltas)):
        avg_gain = (avg_gain * (period - 1) + gain[i]) / period
        avg_loss = (avg_loss * (period - 1) + loss[i]) / period
        
    if avg_loss == 0:
        return 100
    rs = avg_gain / avg_loss
    return 100 - (100 / (1 + rs))

def calculate_bollinger_bands(prices: List[float], period: int = 20, std_dev: float = 2.0) -> Dict[str, float]:
    if len(prices) < period:
        return {}
    sma = sum(prices[-period:]) / period
    variance = sum((p - sma) ** 2 for p in prices[-period:]) / period
    stdev = math.sqrt(variance)
    return {
        "upper": sma + (std_dev * stdev),
        "lower": sma - (std_dev * stdev),
        "middle": sma
    }

def main() -> None:
    ensure_environment()
    session = requests.Session()
    session.headers.update({"X-API-KEY": MAXXIT_API_KEY, "Content-Type": "application/json"})
    
    log(f"Starting Mean Reversion Bot | Market: {MARKET} | Venue: {VENUE}")
    
    # 1. Get Club Details
    club = requests.get(f"{MAXXIT_API_URL}/api/lazy-trading/programmatic/user-details", headers=session.headers).json()
    user_address = club.get("user_wallet")
    agent_address = club.get("ostium_agent_address")

    # 2. Fetch Price Data & Calculate Indicators
    prices = fetch_binance_klines(MARKET)
    if not prices: return
    
    rsi = calculate_rsi(prices, RSI_PERIOD)
    bb = calculate_bollinger_bands(prices, BB_PERIOD, BB_STD)
    current_price = prices[-1]
    
    if rsi is None or not bb: 
        log("Insufficient data for indicators")
        return
        
    log(f"Price: {current_price:.2f} | RSI: {rsi:.2f} | BB: L={bb['lower']:.2f}, U={bb['upper']:.2f}")

    # 3. Determine Signal
    signal = None
    if current_price < bb['lower'] and rsi < RSI_OVERSOLD:
        signal = "long"
    elif current_price > bb['upper'] and rsi > RSI_OVERBOUGHT:
        signal = "short"
        
    if not signal:
        log("No mean reversion signal; skipping.")
        return

    # 4. Check Balance & Positions
    balance_path = f"{VENUE.lower()}/balance" if VENUE == "AVANTIS" else "balance"
    balance_payload = {"userAddress": user_address} if VENUE == "AVANTIS" else {"address": user_address}
    balance = api_post(session, balance_path, balance_payload)
    if not balance: return
    usdc_balance = float(balance.get("usdcBalance", 0))

    pos_path = f"{VENUE.lower()}/positions" if VENUE == "AVANTIS" else "positions"
    pos_payload = {"userAddress": user_address, "agentAddress": agent_address} if VENUE == "AVANTIS" else {"address": user_address}
    positions_resp = api_post(session, pos_path, pos_payload)
    
    # Simple logic: If in a position, don't open another of the same side.
    if positions_resp and positions_resp.get("positions"):
        for pos in positions_resp["positions"]:
            if (pos.get("market") == MARKET or pos.get("marketFull") == SYMBOL) and pos.get("side").lower() == signal:
                log(f"Already in a {signal} position.")
                return

    # 5. Execute
    collateral = min(usdc_balance * COLLATERAL_UTILIZATION, usdc_balance)
    if collateral < 1.0: return

    open_path = f"{VENUE.lower()}/open-position" if VENUE == "AVANTIS" else "open-position"
    open_payload = {
        "agentAddress": agent_address,
        "userAddress": user_address,
        "market": MARKET,
        "side": signal,
        "collateral": round(collateral, 2),
        "leverage": LEVERAGE,
        "takeProfitPercent": 0.015, # Tight TP for mean reversion
        "stopLossPercent": 0.01      # Tight SL
    }
    
    open_resp = api_post(session, open_path, open_payload)
    if open_resp and open_resp.get("success"):
        log(f"Opened {signal} mean-reversion position on {VENUE}")

if __name__ == "__main__":
    main()


path: README.md
content: # Maxxit 0G Skill

Use Maxxit Lazy Trading with 0G decentralized compute for portfolio-aware trade decisions and 0G decentralized storage for verifiable alpha listings.

## Installation

### Via ClawHub CLI
```bash
npx clawhub@latest install maxxit-0g
```

### Manual Installation
Copy the `maxxit-0g` folder to:
- Global: `~/.openclaw/skills/`
- Workspace: `<project>/skills/`

## Configuration

Set these environment variables:

```bash
export MAXXIT_API_KEY="lt_your_api_key_here"
export MAXXIT_API_URL="https://maxxit.ai"
```

## Quick Start

1. **Get an API Key**: 
   - Visit [maxxit.ai/lazy-trading](https://maxxit.ai/lazy-trading)
   - Connect your wallet
   - Complete the setup wizard
   - Generate an API key from your [dashboard](https://www.maxxit.ai/dashboard)

2. **Configure**: Set environment variables

3. **Use**: Ask your assistant to send trading signals!

## Example Usage

```
"Should I trade BTC?"

"What does 0G think about ETH?"

"Make a portfolio-aware AI decision for SOL"

"Send a trading signal: Long ETH 5x leverage at 3200"

"Check my lazy trading account status"

"Execute a short on BTC with 10x leverage, TP 60000, SL 68000"

"List this trade as alpha on 0G storage"
```

## 0G Features

- **0G Compute Decision Workflow**: The skill can call Maxxit's `/alpha/0g-decision` endpoint with your deployment context and market research summary, then present `shouldTrade`, `side`, `confidence`, and `reasoning`.
- **Sponsored Inference**: 0G decisions are sponsored by the platform and do not deduct user LLM credits.
- **0G Storage for Alpha**: When a verified trade is listed as alpha, Maxxit uploads the alpha content to 0G storage when available and returns a `rootHash` for independent buyer verification.

## Supported Venues

- **Ostium** - Perpetual futures on Arbitrum
- **Aster DEX** - Perpetual futures on BNB Chain (testnet setup in Maxxit)
- **Avantis DEX** - Perpetual futures on Base mainnet
- **Alpha Marketplace** - Trustless ZK-verified trading signals with optional 0G storage proofs

## Built-in Strategy Scripts

The skill includes standalone Python strategy scripts. Use them when the user wants the agent to run a predefined trading system.

- `ema-strategy.py` - EMA crossover trend-following strategy
- `rsi-bollinger-strategy.py` - RSI + Bollinger Band mean reversion strategy
- `donchian-adx-strategy.py` - Donchian breakout with ADX trend filter
- `taker-strategy.py` - Aggressive Taker (Order Flow) HFT strategy. Analyzes Binance taker buy/sell ratios to detect aggressive market participants and catch rapid momentum shifts.
- `mean-reversion-strategy.py` - RSI + Bollinger Band mean-reversion strategy. A technical approach using price exhaustion points optimized for high-frequency scalping in sideways or boring markets.
- `breakout-strategy.py` - Volatility breakout strategy with ATR filter. Enters trades when price breaks out of a standard deviation channel while ATR confirms increasing volatility and momentum.
- `vwap-strategy.py` - VWAP crossover institutional momentum strategy. Uses volume-weighted average price and EMA to confirm institutional trend alignment and confirm trade strength with volume.

Each script fetches Binance klines, derives signals locally, and routes execution through the Maxxit Lazy Trading API.

### Command Line Usage
All scripts support dynamic `--symbol` (e.g. `BTC/USD`) and `--venue` (`OSTIUM` or `AVANTIS`) arguments.

```bash
python taker-strategy.py --symbol BTC/USD --venue AVANTIS
python vwap-strategy.py --symbol ETH/USD --venue OSTIUM
```

## Links

- [Maxxit App](https://maxxit.ai)
- [Lazy Trading Setup](https://maxxit.ai/lazy-trading)
- [0G](https://0g.ai)
- [GitHub](https://github.com/Maxxit-ai/maxxit-latest)


Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)