docs: expand AVE Claw Hackathon research with code examples and guides

- Added 3 runnable Python scripts for Data REST, Data WebSocket, and Trading APIs
- Expanded research with 7 new sections:
  - Extended API documentation with full request/response examples
  - Working code examples with CLI commands
  - Security guide (API keys, HMAC signing, private key protection)
  - Testing strategies (dry-run, paper trading, testnets)
  - Troubleshooting guide with error codes
  - Competitive analysis vs DexScreener, Moralis, CoinGecko
  - Quick reference appendix

Research doc grew from 242 to 906 lines
This commit is contained in:
shokollm
2026-04-05 20:52:58 +00:00
parent eabbcd911c
commit 90283d7403
5 changed files with 2217 additions and 38 deletions

View File

@@ -0,0 +1,494 @@
#!/usr/bin/env python3
"""
AVE Cloud Data REST API - Token Search, Prices, Klines, Holders, Risk
Usage:
export AVE_API_KEY=your_api_key_here
export API_PLAN=free # free, normal, pro
python3 docs/scripts/ave_data_rest.py search --keyword PEPE
python3 docs/scripts/ave_data_rest.py price --token-ids "PEPE-bsc,TRUMP-bsc"
python3 docs/scripts/ave_data_rest.py trending --chain bsc
python3 docs/scripts/ave_data_rest.py token --token-id "0x6982508145454Ce325dDbE47a25d4ec3d2311933-bsc"
python3 docs/scripts/ave_data_rest.py risk --token-id "0x6982508145454Ce325dDbE47a25d4ec3d2311933-bsc"
python3 docs/scripts/ave_data_rest.py holders --token-id "0x6982508145454Ce325dDbE47a25d4ec3d2311933-bsc"
python3 docs/scripts/ave_data_rest.py klines --token-id "0x6982508145454Ce325dDbE47a25d4ec3d2311933-bsc"
python3 docs/scripts/ave_data_rest.py pairs --pair-id "0x16b9a82891338f9ba80e2d6970fdda79d1eb0dae-bsc"
python3 docs/scripts/ave_data_rest.py wallet-pnl --wallet "0xd9c500dff816a1da21a48a732d3498bf09dc9aeb" --chain bsc --token "0x55d398326f99059fF775485246999027B3197955"
python3 docs/scripts/ave_data_rest.py wallet-info --wallet "0xd9c500dff816a1da21a48a732d3498bf09dc9aeb" --chain bsc
python3 docs/scripts/ave_data_rest.py smart-wallets --chain bsc
"""
import argparse
import json
import os
import sys
import time
from dataclasses import dataclass
from typing import Optional
import requests
BASE_URL = "https://prod.ave-api.com"
API_KEY = os.getenv("AVE_API_KEY", "")
API_PLAN = os.getenv("API_PLAN", "free")
CU_COSTS = {
"search": 5,
"price": 100,
"trending": 5,
"token": 5,
"risk": 10,
"holders": 10,
"klines_token": 10,
"klines_pair": 10,
"pairs": 5,
"wallet_pnl": 5,
"wallet_info": 5,
"wallet_tokens": 10,
"smart_wallet": 5,
}
TIER_LIMITS = {
"free": {"tps": 1, "data_wss": False, "proxy_wallet": False},
"normal": {"tps": 5, "data_wss": False, "proxy_wallet": True},
"pro": {"tps": 20, "data_wss": True, "proxy_wallet": True},
}
@dataclass
class ApiResponse:
status: int
data: Optional[dict] = None
error: Optional[str] = None
def make_headers():
return {
"X-API-KEY": API_KEY,
"Content-Type": "application/json",
}
def handle_response(response: requests.Response) -> ApiResponse:
if response.status_code == 200:
return ApiResponse(status=200, data=response.json())
elif response.status_code == 401:
return ApiResponse(
status=401, error="Unauthorized - invalid or missing API key"
)
elif response.status_code == 403:
return ApiResponse(
status=403, error="Forbidden - API key expired or plan limits reached"
)
elif response.status_code == 429:
return ApiResponse(status=429, error="Rate limited - TPS exceeded")
else:
return ApiResponse(status=response.status_code, error=response.text)
def search_tokens(
keyword: str, chain: Optional[str] = None, limit: int = 100
) -> ApiResponse:
params = {"keyword": keyword, "limit": limit}
if chain:
params["chain"] = chain
response = requests.get(
f"{BASE_URL}/v2/tokens", headers=make_headers(), params=params
)
return handle_response(response)
def get_token_price(token_ids: list) -> ApiResponse:
data = {"token_ids": token_ids}
response = requests.post(
f"{BASE_URL}/v2/tokens/price", headers=make_headers(), json=data
)
return handle_response(response)
def get_trending_tokens(chain: str, page: int = 0, page_size: int = 50) -> ApiResponse:
params = {"chain": chain, "current_page": page, "page_size": page_size}
response = requests.get(
f"{BASE_URL}/v2/tokens/trending", headers=make_headers(), params=params
)
return handle_response(response)
def get_token_detail(token_id: str) -> ApiResponse:
response = requests.get(f"{BASE_URL}/v2/tokens/{token_id}", headers=make_headers())
return handle_response(response)
def get_token_risk(token_id: str) -> ApiResponse:
response = requests.get(
f"{BASE_URL}/v2/contracts/{token_id}", headers=make_headers()
)
return handle_response(response)
def get_top_holders(token_id: str, limit: int = 100) -> ApiResponse:
params = {"limit": limit} if limit != 100 else {}
response = requests.get(
f"{BASE_URL}/v2/tokens/top100/{token_id}", headers=make_headers(), params=params
)
return handle_response(response)
def get_klines_by_token(
token_id: str, interval: str = "1h", limit: int = 100
) -> ApiResponse:
params = {"interval": interval, "limit": limit}
response = requests.get(
f"{BASE_URL}/v2/klines/token/{token_id}", headers=make_headers(), params=params
)
return handle_response(response)
def get_klines_by_pair(
pair_id: str, interval: str = "1h", limit: int = 100
) -> ApiResponse:
params = {"interval": interval, "limit": limit}
response = requests.get(
f"{BASE_URL}/v2/klines/pair/{pair_id}", headers=make_headers(), params=params
)
return handle_response(response)
def get_pair_detail(pair_id: str) -> ApiResponse:
response = requests.get(f"{BASE_URL}/v2/pairs/{pair_id}", headers=make_headers())
return handle_response(response)
def get_wallet_pnl(
wallet_address: str,
chain: str,
token_address: str,
from_time: Optional[int] = None,
to_time: Optional[int] = None,
) -> ApiResponse:
params = {
"wallet_address": wallet_address,
"chain": chain,
"token_address": token_address,
}
if from_time:
params["from_time"] = from_time
if to_time:
params["to_time"] = to_time
response = requests.get(
f"{BASE_URL}/v2/address/pnl", headers=make_headers(), params=params
)
return handle_response(response)
def get_wallet_info(wallet_address: str, chain: str) -> ApiResponse:
params = {"wallet_address": wallet_address, "chain": chain}
response = requests.get(
f"{BASE_URL}/v2/address/walletinfo", headers=make_headers(), params=params
)
return handle_response(response)
def get_wallet_tokens(
wallet_address: str,
chain: str,
sort: str = "last_txn_time",
sort_dir: str = "desc",
hide_sold: int = 0,
hide_small: int = 0,
) -> ApiResponse:
params = {
"wallet_address": wallet_address,
"chain": chain,
"sort": sort,
"sort_dir": sort_dir,
"hide_sold": hide_sold,
"hide_small": hide_small,
}
response = requests.get(
f"{BASE_URL}/v2/address/walletinfo/tokens",
headers=make_headers(),
params=params,
)
return handle_response(response)
def get_smart_wallets(
chain: str, sort: str = "total_profit", sort_dir: str = "desc"
) -> ApiResponse:
params = {"chain": chain, "sort": sort, "sort_dir": sort_dir}
response = requests.get(
f"{BASE_URL}/v2/address/smart_wallet/list",
headers=make_headers(),
params=params,
)
return handle_response(response)
def format_json(data):
return json.dumps(data, indent=2, ensure_ascii=False)
def print_cu_warning(operation: str):
cu_cost = CU_COSTS.get(operation, "unknown")
print(f"[CU Cost: {cu_cost}]", file=sys.stderr)
def cmd_search(args):
result = search_tokens(args.keyword, args.chain, args.limit)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("search")
print(format_json(result.data))
def cmd_price(args):
token_ids = [t.strip() for t in args.token_ids.split(",")]
result = get_token_price(token_ids)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("price")
print(format_json(result.data))
def cmd_trending(args):
result = get_trending_tokens(args.chain, args.page, args.page_size)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("trending")
print(format_json(result.data))
def cmd_token(args):
result = get_token_detail(args.token_id)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("token")
print(format_json(result.data))
def cmd_risk(args):
result = get_token_risk(args.token_id)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("risk")
print(format_json(result.data))
def cmd_holders(args):
result = get_top_holders(args.token_id, args.limit)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("holders")
print(format_json(result.data))
def cmd_klines(args):
if args.pair_id:
result = get_klines_by_pair(args.pair_id, args.interval, args.limit)
print_cu_warning("klines_pair")
else:
result = get_klines_by_token(args.token_id, args.interval, args.limit)
print_cu_warning("klines_token")
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print(format_json(result.data))
def cmd_pairs(args):
result = get_pair_detail(args.pair_id)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("pairs")
print(format_json(result.data))
def cmd_wallet_pnl(args):
result = get_wallet_pnl(
args.wallet, args.chain, args.token, args.from_time, args.to_time
)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("wallet_pnl")
print(format_json(result.data))
def cmd_wallet_info(args):
result = get_wallet_info(args.wallet, args.chain)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("wallet_info")
print(format_json(result.data))
def cmd_wallet_tokens(args):
result = get_wallet_tokens(
args.wallet,
args.chain,
args.sort,
args.sort_dir,
args.hide_sold,
args.hide_small,
)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("wallet_tokens")
print(format_json(result.data))
def cmd_smart_wallets(args):
result = get_smart_wallets(args.chain, args.sort, args.sort_dir)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("smart_wallet")
print(format_json(result.data))
def main():
parser = argparse.ArgumentParser(description="AVE Cloud Data REST API")
parser.add_argument(
"--api-key", default=API_KEY, help="AVE API key (or set AVE_API_KEY env)"
)
parser.add_argument(
"--api-plan",
default=API_PLAN,
choices=["free", "normal", "pro"],
help="API plan",
)
subparsers = parser.add_subparsers(dest="command", help="Commands")
p_search = subparsers.add_parser("search", help="Search tokens by keyword")
p_search.add_argument("--keyword", required=True, help="Token symbol or address")
p_search.add_argument("--chain", help="Chain name (bsc, solana, eth, base)")
p_search.add_argument(
"--limit", type=int, default=100, help="Number of results (max 300)"
)
p_price = subparsers.add_parser("price", help="Get batch token prices")
p_price.add_argument(
"--token-ids",
required=True,
help="Comma-separated token IDs (e.g. PEPE-bsc,TRUMP-bsc)",
)
p_trending = subparsers.add_parser("trending", help="Get trending tokens")
p_trending.add_argument("--chain", required=True, help="Chain name")
p_trending.add_argument("--page", type=int, default=0, help="Page number")
p_trending.add_argument(
"--page-size", type=int, default=50, help="Results per page (max 100)"
)
p_token = subparsers.add_parser("token", help="Get token details and top pairs")
p_token.add_argument(
"--token-id", required=True, help="Token ID (address-chain format)"
)
p_risk = subparsers.add_parser("risk", help="Get token risk information")
p_risk.add_argument(
"--token-id", required=True, help="Token ID (address-chain format)"
)
p_holders = subparsers.add_parser("holders", help="Get top 100 token holders")
p_holders.add_argument(
"--token-id", required=True, help="Token ID (address-chain format)"
)
p_holders.add_argument(
"--limit", type=int, default=100, help="Number of holders (max 100)"
)
p_klines = subparsers.add_parser("klines", help="Get kline/candlestick data")
p_klines.add_argument("--token-id", help="Token ID (use OR --pair-id)")
p_klines.add_argument("--pair-id", help="Pair ID (use OR --token-id)")
p_klines.add_argument(
"--interval", default="1h", help="Interval (1m, 5m, 15m, 30m, 1h, 4h, 1d)"
)
p_klines.add_argument("--limit", type=int, default=100, help="Number of klines")
p_pairs = subparsers.add_parser("pairs", help="Get pair details")
p_pairs.add_argument(
"--pair-id", required=True, help="Pair ID (address-chain format)"
)
p_wallet_pnl = subparsers.add_parser(
"wallet-pnl", help="Get wallet PnL for a token"
)
p_wallet_pnl.add_argument("--wallet", required=True, help="Wallet address")
p_wallet_pnl.add_argument("--chain", required=True, help="Chain name")
p_wallet_pnl.add_argument("--token", required=True, help="Token address")
p_wallet_pnl.add_argument(
"--from-time", type=int, help="Unix epoch seconds (earliest 15 days ago)"
)
p_wallet_pnl.add_argument("--to-time", type=int, help="Unix epoch seconds")
p_wallet_info = subparsers.add_parser(
"wallet-info", help="Get wallet info (all tokens on chain)"
)
p_wallet_info.add_argument("--wallet", required=True, help="Wallet address")
p_wallet_info.add_argument("--chain", required=True, help="Chain name")
p_wallet_tokens = subparsers.add_parser(
"wallet-tokens", help="Get all tokens holding in wallet"
)
p_wallet_tokens.add_argument("--wallet", required=True, help="Wallet address")
p_wallet_tokens.add_argument("--chain", required=True, help="Chain name")
p_wallet_tokens.add_argument("--sort", default="last_txn_time", help="Sort field")
p_wallet_tokens.add_argument(
"--sort-dir", default="desc", help="Sort direction (desc/asc)"
)
p_wallet_tokens.add_argument(
"--hide-sold", type=int, default=0, help="Hide sold tokens (0/1)"
)
p_wallet_tokens.add_argument(
"--hide-small", type=int, default=0, help="Hide small balances (0/1)"
)
p_smart = subparsers.add_parser(
"smart-wallets", help="Get smart wallet list (for copy trading)"
)
p_smart.add_argument("--chain", required=True, help="Chain name")
p_smart.add_argument("--sort", default="total_profit", help="Sort field")
p_smart.add_argument("--sort-dir", default="desc", help="Sort direction (desc/asc)")
args = parser.parse_args()
if not args.api_key:
print("Error: API key required. Set AVE_API_KEY env or use --api-key")
sys.exit(1)
if not args.command:
parser.print_help()
sys.exit(1)
cmd_map = {
"search": cmd_search,
"price": cmd_price,
"trending": cmd_trending,
"token": cmd_token,
"risk": cmd_risk,
"holders": cmd_holders,
"klines": cmd_klines,
"pairs": cmd_pairs,
"wallet-pnl": cmd_wallet_pnl,
"wallet-info": cmd_wallet_info,
"wallet-tokens": cmd_wallet_tokens,
"smart-wallets": cmd_smart_wallets,
}
cmd_map[args.command](args)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,459 @@
#!/usr/bin/env python3
"""
AVE Cloud Data WebSocket API - Real-time Streams
Usage:
export AVE_API_KEY=your_api_key_here
export API_PLAN=pro # REQUIRED for WebSocket (must be 'pro')
python3 docs/scripts/ave_data_wss.py subscribe-tx --pair "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE" --chain solana
python3 docs/scripts/ave_data_wss.py subscribe-multi-tx --token "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c" --chain bsc
python3 docs/scripts/ave_data_wss.py subscribe-liq --pair "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE" --chain solana
python3 docs/scripts/ave_data_wss.py subscribe-price --pairs "PEPE-bsc,TRUMP-bsc"
python3 docs/scripts/ave_data_wss.py subscribe-kline --token "0x6982508145454Ce325dDbE47a25d4ec3d2311933-bsc" --interval 1m
python3 docs/scripts/ave_data_wss.py wss-repl # Interactive REPL mode
Notes:
- WebSocket API requires API_PLAN=pro
- Max 5 concurrent WebSocket connections
- Auto-reconnect with exponential backoff on disconnect
"""
import argparse
import json
import os
import sys
import time
from dataclasses import dataclass, field
from typing import Optional
import websocket
WSS_URL = "wss://wss.ave-api.xyz"
API_KEY = os.getenv("AVE_API_KEY", "")
API_PLAN = os.getenv("API_PLAN", "")
@dataclass
class WssMessage:
id: int
method: str
params: list
result: Optional[dict] = None
@dataclass
class WssSubscription:
topic: str
address: str
chain: str
id: int
class AveWssClient:
def __init__(self, api_key: str, debug: bool = False):
self.api_key = api_key
self.debug = debug
self.ws: Optional[websocket.WebSocket] = None
self.subscription_id = 1
self.subscriptions: list[WssSubscription] = []
self.running = False
def connect(self):
if self.ws:
self.disconnect()
self.ws = websocket.WebSocketApp(
WSS_URL,
on_open=self._on_open,
on_message=self._on_message,
on_error=self._on_error,
on_close=self._on_close,
)
self.running = True
def disconnect(self):
self.running = False
if self.ws:
self.ws.close()
self.ws = None
def _on_open(self, ws):
print("[Connected to WebSocket]", file=sys.stderr)
def _on_message(self, ws, message):
try:
data = json.loads(message)
if self.debug:
print(f"[DEBUG] {json.dumps(data, indent=2)}", file=sys.stderr)
if "result" in data and data.get("id"):
for sub in self.subscriptions:
if sub.id == data["id"]:
sub.id = data["result"].get("id", data["id"])
print(
f"[Subscribed to {sub.topic}] {sub.address} on {sub.chain}",
file=sys.stderr,
)
break
elif "params" in data:
topic = data["params"].get("topic", "unknown")
if topic == "tx":
self._handle_tx(data["params"]["data"])
elif topic == "liq":
self._handle_liq(data["params"]["data"])
elif topic == "kline":
self._handle_kline(data["params"]["data"])
elif topic == "price":
self._handle_price(data["params"]["data"])
except json.JSONDecodeError:
print(f"[Error] Failed to parse message: {message}", file=sys.stderr)
def _on_error(self, ws, error):
print(f"[WebSocket Error] {error}", file=sys.stderr)
def _on_close(self, ws, close_status_code, close_msg):
print(f"[Disconnected] {close_status_code}: {close_msg}", file=sys.stderr)
self.running = False
def _handle_tx(self, tx: dict):
print(
f"[TX] {tx.get('chain')}: {tx.get('from_symbol')} -> {tx.get('to_symbol')} "
f"Amount: {tx.get('from_amount')} {tx.get('from_symbol')} | "
f"Sender: {tx.get('sender', 'unknown')[:10]}... | "
f"Pair: {tx.get('pair_address', 'unknown')[:15]}..."
)
def _handle_liq(self, liq: dict):
print(
f"[LIQ] {liq.get('chain')}: {liq.get('action')} "
f"Amount: {liq.get('amount')} {liq.get('symbol')} | "
f"Pair: {liq.get('pair_address', 'unknown')[:15]}..."
)
def _handle_kline(self, kline: dict):
print(
f"[KLINE] {kline.get('token_id', kline.get('pair_id'))} "
f"{kline.get('interval')}: O={kline.get('open')} H={kline.get('high')} "
f"L={kline.get('low')} C={kline.get('close')} V={kline.get('volume')}"
)
def _handle_price(self, price: dict):
print(
f"[PRICE] {price.get('token_id', price.get('pair_id'))}: "
f"{price.get('price')} USD (change: {price.get('price_change_24h', 'N/A')}%)"
)
def _send(self, method: str, params: list, timeout: int = 10) -> Optional[dict]:
if not self.ws:
return None
msg_id = self.subscription_id
self.subscription_id += 1
msg = {"jsonrpc": "2.0", "method": method, "params": params, "id": msg_id}
self.ws.send(json.dumps(msg))
return {"id": msg_id}
def subscribe_tx(self, pair_address: str, chain: str):
params = ["tx", pair_address, chain]
result = self._send("subscribe", params)
if result:
self.subscriptions.append(
WssSubscription(
topic="tx", address=pair_address, chain=chain, id=result["id"]
)
)
def subscribe_multi_tx(self, token_address: str, chain: str):
params = ["multi_tx", token_address, chain]
result = self._send("subscribe", params)
if result:
self.subscriptions.append(
WssSubscription(
topic="multi_tx",
address=token_address,
chain=chain,
id=result["id"],
)
)
def subscribe_liq(self, pair_address: str, chain: str):
params = ["liq", pair_address, chain]
result = self._send("subscribe", params)
if result:
self.subscriptions.append(
WssSubscription(
topic="liq", address=pair_address, chain=chain, id=result["id"]
)
)
def subscribe_price(self, pairs: list):
params = ["price", pairs]
result = self._send("subscribe", params)
if result:
for pair in pairs:
self.subscriptions.append(
WssSubscription(
topic="price", address=pair, chain="multi", id=result["id"]
)
)
def subscribe_kline(self, token_or_pair_id: str, interval: str = "1m"):
params = ["kline", token_or_pair_id, interval]
result = self._send("subscribe", params)
if result:
self.subscriptions.append(
WssSubscription(
topic="kline",
address=token_or_pair_id,
chain=interval,
id=result["id"],
)
)
def unsubscribe(self, topic: str, address: str, chain: str):
params = (
["unsubscribe", topic, address, chain]
if chain != "multi"
else ["unsubscribe", topic, address]
)
self._send("unsubscribe", params)
self.subscriptions = [
s
for s in self.subscriptions
if not (s.topic == topic and s.address == address and s.chain == chain)
]
def run_forever(self, reconnect_delay: int = 5, max_reconnect_delay: int = 60):
delay = reconnect_delay
while self.running:
try:
self.ws.run_forever(ping_interval=30, ping_timeout=10)
except Exception as e:
print(f"[Error] {e}", file=sys.stderr)
if self.running:
print(f"[Reconnecting in {delay}s...]", file=sys.stderr)
time.sleep(delay)
delay = min(delay * 2, max_reconnect_delay)
self.connect()
def cmd_subscribe_tx(args):
if API_PLAN != "pro":
print("Error: WebSocket requires API_PLAN=pro", file=sys.stderr)
sys.exit(1)
client = AveWssClient(args.api_key, debug=args.debug)
client.connect()
client.subscribe_tx(args.pair, args.chain)
print("[Press Ctrl+C to exit]", file=sys.stderr)
try:
client.run_forever()
except KeyboardInterrupt:
client.disconnect()
def cmd_subscribe_multi_tx(args):
if API_PLAN != "pro":
print("Error: WebSocket requires API_PLAN=pro", file=sys.stderr)
sys.exit(1)
client = AveWssClient(args.api_key, debug=args.debug)
client.connect()
client.subscribe_multi_tx(args.token, args.chain)
print("[Press Ctrl+C to exit]", file=sys.stderr)
try:
client.run_forever()
except KeyboardInterrupt:
client.disconnect()
def cmd_subscribe_liq(args):
if API_PLAN != "pro":
print("Error: WebSocket requires API_PLAN=pro", file=sys.stderr)
sys.exit(1)
client = AveWssClient(args.api_key, debug=args.debug)
client.connect()
client.subscribe_liq(args.pair, args.chain)
print("[Press Ctrl+C to exit]", file=sys.stderr)
try:
client.run_forever()
except KeyboardInterrupt:
client.disconnect()
def cmd_subscribe_price(args):
if API_PLAN != "pro":
print("Error: WebSocket requires API_PLAN=pro", file=sys.stderr)
sys.exit(1)
pairs = [p.strip() for p in args.pairs.split(",")]
client = AveWssClient(args.api_key, debug=args.debug)
client.connect()
client.subscribe_price(pairs)
print("[Press Ctrl+C to exit]", file=sys.stderr)
try:
client.run_forever()
except KeyboardInterrupt:
client.disconnect()
def cmd_subscribe_kline(args):
if API_PLAN != "pro":
print("Error: WebSocket requires API_PLAN=pro", file=sys.stderr)
sys.exit(1)
client = AveWssClient(args.api_key, debug=args.debug)
client.connect()
client.subscribe_kline(args.token, args.interval)
print("[Press Ctrl+C to exit]", file=sys.stderr)
try:
client.run_forever()
except KeyboardInterrupt:
client.disconnect()
def cmd_wss_repl(args):
if API_PLAN != "pro":
print("Error: WebSocket requires API_PLAN=pro", file=sys.stderr)
sys.exit(1)
client = AveWssClient(args.api_key, debug=args.debug)
client.connect()
print(
"[WebSocket REPL - type 'help' for commands, 'quit' to exit]", file=sys.stderr
)
print(
"[Commands: subscribe tx <pair> <chain>, subscribe price <pairs>, unsubscribe <topic> <addr> <chain>]",
file=sys.stderr,
)
subscriptions = []
def print_help():
print("Commands:")
print(
" subscribe tx <pair_address> <chain> - Subscribe to swap transactions by pair"
)
print(
" subscribe multi_tx <token_address> <chain> - Subscribe to all txs involving a token"
)
print(
" subscribe liq <pair_address> <chain> - Subscribe to liquidity changes by pair"
)
print(" subscribe price <pair1,pair2,...> - Subscribe to price changes")
print(
" subscribe kline <token_id> <interval> - Subscribe to kline data (interval: 1m, 5m, etc.)"
)
print(" unsubscribe <topic> <address> <chain> - Unsubscribe")
print(" list - List subscriptions")
print(" help - Show this help")
print(" quit - Exit")
while True:
try:
user_input = input("wss> ").strip()
if not user_input:
continue
parts = user_input.split()
cmd = parts[0].lower()
if cmd == "quit":
break
elif cmd == "help":
print_help()
elif cmd == "list":
for s in client.subscriptions:
print(f" {s.topic}: {s.address} on {s.chain}")
elif cmd == "subscribe" and len(parts) >= 3:
sub_type = parts[1].lower()
if sub_type == "tx" and len(parts) >= 4:
client.subscribe_tx(parts[2], parts[3])
elif sub_type == "multi_tx" and len(parts) >= 4:
client.subscribe_multi_tx(parts[2], parts[3])
elif sub_type == "liq" and len(parts) >= 4:
client.subscribe_liq(parts[2], parts[3])
elif sub_type == "price" and len(parts) >= 3:
pairs = parts[2].split(",")
client.subscribe_price(pairs)
elif sub_type == "kline" and len(parts) >= 4:
client.subscribe_kline(parts[2], parts[3])
else:
print("Invalid subscribe command")
elif cmd == "unsubscribe" and len(parts) >= 4:
client.unsubscribe(parts[1], parts[2], parts[3])
else:
print("Unknown command. Type 'help' for commands.")
except KeyboardInterrupt:
break
except EOFError:
break
client.disconnect()
print("\n[Exited]")
def main():
parser = argparse.ArgumentParser(description="AVE Cloud Data WebSocket API")
parser.add_argument(
"--api-key", default=API_KEY, help="AVE API key (or set AVE_API_KEY env)"
)
parser.add_argument(
"--api-plan", default=API_PLAN, help="API plan (or set API_PLAN env)"
)
parser.add_argument("--debug", action="store_true", help="Enable debug output")
subparsers = parser.add_subparsers(dest="command", help="Commands")
p_tx = subparsers.add_parser(
"subscribe-tx", help="Subscribe to swap transactions by pair"
)
p_tx.add_argument("--pair", required=True, help="Pair address")
p_tx.add_argument(
"--chain", required=True, help="Chain name (solana, bsc, eth, base)"
)
p_multi = subparsers.add_parser(
"subscribe-multi-tx", help="Subscribe to all txs involving a token"
)
p_multi.add_argument("--token", required=True, help="Token address")
p_multi.add_argument("--chain", required=True, help="Chain name")
p_liq = subparsers.add_parser(
"subscribe-liq", help="Subscribe to liquidity changes by pair"
)
p_liq.add_argument("--pair", required=True, help="Pair address")
p_liq.add_argument("--chain", required=True, help="Chain name")
p_price = subparsers.add_parser(
"subscribe-price", help="Subscribe to price changes"
)
p_price.add_argument(
"--pairs", required=True, help="Comma-separated pairs (e.g. PEPE-bsc,TRUMP-bsc)"
)
p_kline = subparsers.add_parser("subscribe-kline", help="Subscribe to kline data")
p_kline.add_argument(
"--token", required=True, help="Token ID (address-chain format)"
)
p_kline.add_argument(
"--interval", default="1m", help="Interval (1m, 5m, 15m, 30m, 1h, 4h, 1d)"
)
subparsers.add_parser("wss-repl", help="Interactive WebSocket REPL")
args = parser.parse_args()
if not args.api_key:
print("Error: API key required. Set AVE_API_KEY env or use --api-key")
sys.exit(1)
if not args.command:
parser.print_help()
sys.exit(1)
cmd_map = {
"subscribe-tx": cmd_subscribe_tx,
"subscribe-multi-tx": cmd_subscribe_multi_tx,
"subscribe-liq": cmd_subscribe_liq,
"subscribe-price": cmd_subscribe_price,
"subscribe-kline": cmd_subscribe_kline,
"wss-repl": cmd_wss_repl,
}
cmd_map[args.command](args)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,560 @@
#!/usr/bin/env python3
"""
AVE Cloud Trading REST API - Chain Wallet & Proxy Wallet Trading
Usage:
# Environment setup
export AVE_API_KEY=your_api_key_here
export API_PLAN=free # free for chain-wallet, normal/pro for proxy-wallet
export AVE_SECRET_KEY=your_secret_key_here # For proxy wallet HMAC signing
# Chain Wallet (Self-custody) - Free tier OK
python3 docs/scripts/ave_trade_rest.py chain-quote --chain bsc --in-token 0x55d398326f99059fF775485246999027B3197955 --out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c --in-amount 10000000 --swap-type buy
python3 docs/scripts/ave_trade_rest.py chain-swap --chain bsc --in-token 0x55d398326f99059fF775485246999027B3197955 --out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c --in-amount 10000000 --swap-type buy
# Proxy Wallet (Server-managed) - Requires normal/pro tier
python3 docs/scripts/ave_trade_rest.py proxy-quote --chain bsc --in-token 0x55d398326f99059fF775485246999027B3197955 --out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c --in-amount 10000000 --swap-type buy
python3 docs/scripts/ave_trade_rest.py proxy-market --chain bsc --in-token 0x55d398326f99059fF775485246999027B3197955 --out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c --in-amount 10000000 --swap-type buy
python3 docs/scripts/ave_trade_rest.py proxy-limit --chain bsc --in-token 0x55d398326f99059fF775485246999027B3197955 --out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c --in-amount 10000000 --swap-type buy --price 35.5
python3 docs/scripts/ave_trade_rest.py proxy-orders --chain bsc
python3 docs/scripts/ave_trade_rest.py proxy-cancel --chain bsc --order-id xxx
# Wallet Management
python3 docs/scripts/ave_trade_rest.py create-proxy-wallet --chain bsc
python3 docs/scripts/ave_trade_rest.py list-proxy-wallets --chain bsc
Notes:
- Chain Wallet: Requires API_PLAN=free or higher
- Proxy Wallet: Requires API_PLAN=normal or pro
- All amount fields use string format to avoid floating point precision issues
- Proxy wallet uses HMAC-SHA256 signing with AVE_SECRET_KEY
"""
import argparse
import hashlib
import hmac
import json
import os
import sys
import time
from dataclasses import dataclass
from datetime import datetime, timezone
from typing import Optional
import requests
CHAIN_WALLET_URL = "https://bot-api.ave.ai"
PROXY_WALLET_URL = "https://bot-api.ave.ai"
API_KEY = os.getenv("AVE_API_KEY", "")
API_PLAN = os.getenv("API_PLAN", "free")
SECRET_KEY = os.getenv("AVE_SECRET_KEY", "")
EVM_PRIVATE_KEY = os.getenv("AVE_EVM_PRIVATE_KEY", "")
SOLANA_PRIVATE_KEY = os.getenv("AVE_SOLANA_PRIVATE_KEY", "")
@dataclass
class TradeResponse:
status: int
data: Optional[dict] = None
error: Optional[str] = None
business_code: Optional[int] = None
def make_headers(signed: bool = False):
headers = {
"X-API-KEY": API_KEY,
"Content-Type": "application/json",
}
return headers
def make_proxy_headers(timestamp: str, signature: str):
return {
"X-API-KEY": API_KEY,
"X-Signature": signature,
"X-Timestamp": timestamp,
"Content-Type": "application/json",
}
def generate_hmac_signature(timestamp: str, body: str = "") -> str:
message = timestamp + body
signature = hmac.new(
SECRET_KEY.encode(), message.encode(), hashlib.sha256
).hexdigest()
return signature
def handle_response(response: requests.Response) -> TradeResponse:
if response.status_code == 200:
data = response.json()
if data.get("code") == 200 or data.get("status") == 200:
return TradeResponse(status=200, data=data)
else:
return TradeResponse(
status=data.get("code", response.status_code),
data=data,
error=data.get("msg", "Unknown error"),
business_code=data.get("code"),
)
elif response.status_code == 401:
return TradeResponse(
status=401, error="Unauthorized - invalid or missing API key"
)
elif response.status_code == 403:
return TradeResponse(
status=403,
error="Forbidden - API key expired, plan limits, or insufficient permissions",
)
elif response.status_code == 429:
return TradeResponse(status=429, error="Rate limited - TPS exceeded")
else:
try:
data = response.json()
return TradeResponse(
status=response.status_code,
data=data,
error=data.get("msg", response.text),
business_code=data.get("code"),
)
except json.JSONDecodeError:
return TradeResponse(status=response.status_code, error=response.text)
def chain_quote(
chain: str,
in_token: str,
out_token: str,
in_amount: str,
swap_type: str,
slippage: float = 0.5,
) -> TradeResponse:
endpoint = f"{CHAIN_WALLET_URL}/v1/chain/quote"
data = {
"chain": chain,
"in_token": in_token,
"out_token": out_token,
"in_amount": in_amount,
"swap_type": swap_type,
"slippage": slippage,
}
response = requests.post(endpoint, headers=make_headers(), json=data)
return handle_response(response)
def chain_swap(
chain: str,
in_token: str,
out_token: str,
in_amount: str,
swap_type: str,
slippage: float = 0.5,
recipient: Optional[str] = None,
) -> TradeResponse:
endpoint = f"{CHAIN_WALLET_URL}/v1/chain/swap"
data = {
"chain": chain,
"in_token": in_token,
"out_token": out_token,
"in_amount": in_amount,
"swap_type": swap_type,
"slippage": slippage,
}
if recipient:
data["recipient"] = recipient
response = requests.post(endpoint, headers=make_headers(), json=data)
return handle_response(response)
def proxy_quote(
chain: str,
proxy_wallet: str,
in_token: str,
out_token: str,
in_amount: str,
swap_type: str,
) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
body = json.dumps(
{
"chain": chain,
"proxy_wallet": proxy_wallet,
"in_token": in_token,
"out_token": out_token,
"in_amount": in_amount,
"swap_type": swap_type,
},
separators=(",", ":"),
)
signature = generate_hmac_signature(timestamp, body)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/quote"
response = requests.post(endpoint, headers=headers, json=json.loads(body))
return handle_response(response)
def proxy_market_order(
chain: str,
proxy_wallet: str,
in_token: str,
out_token: str,
in_amount: str,
swap_type: str,
tp_price: Optional[str] = None,
sl_price: Optional[str] = None,
trailing_stop: Optional[dict] = None,
) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
data = {
"chain": chain,
"proxy_wallet": proxy_wallet,
"in_token": in_token,
"out_token": out_token,
"in_amount": in_amount,
"swap_type": swap_type,
"order_type": "market",
}
if tp_price:
data["tp_price"] = tp_price
if sl_price:
data["sl_price"] = sl_price
if trailing_stop:
data["trailing_stop"] = trailing_stop
body = json.dumps(data, separators=(",", ":"))
signature = generate_hmac_signature(timestamp, body)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/market_order"
response = requests.post(endpoint, headers=headers, json=data)
return handle_response(response)
def proxy_limit_order(
chain: str,
proxy_wallet: str,
in_token: str,
out_token: str,
in_amount: str,
swap_type: str,
price: str,
tp_price: Optional[str] = None,
sl_price: Optional[str] = None,
) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
data = {
"chain": chain,
"proxy_wallet": proxy_wallet,
"in_token": in_token,
"out_token": out_token,
"in_amount": in_amount,
"swap_type": swap_type,
"price": price,
"order_type": "limit",
}
if tp_price:
data["tp_price"] = tp_price
if sl_price:
data["sl_price"] = sl_price
body = json.dumps(data, separators=(",", ":"))
signature = generate_hmac_signature(timestamp, body)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/limit_order"
response = requests.post(endpoint, headers=headers, json=data)
return handle_response(response)
def proxy_cancel_order(chain: str, order_id: str) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
data = {"chain": chain, "order_id": order_id}
body = json.dumps(data, separators=(",", ":"))
signature = generate_hmac_signature(timestamp, body)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/cancel_order"
response = requests.post(endpoint, headers=headers, json=data)
return handle_response(response)
def proxy_get_orders(
chain: str, proxy_wallet: str, order_type: Optional[str] = None
) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
params = {"chain": chain, "proxy_wallet": proxy_wallet}
if order_type:
params["order_type"] = order_type
query_string = "&".join([f"{k}={v}" for k, v in sorted(params.items())])
signature = generate_hmac_signature(timestamp, query_string)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/orders"
response = requests.get(endpoint, headers=headers, params=params)
return handle_response(response)
def proxy_get_order_history(chain: str, proxy_wallet: str) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
params = {"chain": chain, "proxy_wallet": proxy_wallet}
query_string = "&".join([f"{k}={v}" for k, v in sorted(params.items())])
signature = generate_hmac_signature(timestamp, query_string)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/order_history"
response = requests.get(endpoint, headers=headers, params=params)
return handle_response(response)
def create_proxy_wallet(chain: str) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
data = {"chain": chain}
body = json.dumps(data, separators=(",", ":"))
signature = generate_hmac_signature(timestamp, body)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/create_proxy_wallet"
response = requests.post(endpoint, headers=headers, json=data)
return handle_response(response)
def list_proxy_wallets(chain: str) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
params = {"chain": chain}
query_string = "&".join([f"{k}={v}" for k, v in sorted(params.items())])
signature = generate_hmac_signature(timestamp, query_string)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/proxy_wallets"
response = requests.get(endpoint, headers=headers, params=params)
return handle_response(response)
def format_json(data):
return json.dumps(data, indent=2, ensure_ascii=False)
def print_trade_response(result: TradeResponse, success_msg: str = "Success"):
if result.error:
print(f"Error ({result.business_code or result.status}): {result.error}")
if result.data:
print(format_json(result.data))
sys.exit(1)
else:
print(f"{success_msg}")
if result.data:
print(format_json(result.data))
def cmd_chain_quote(args):
result = chain_quote(
chain=args.chain,
in_token=args.in_token,
out_token=args.out_token,
in_amount=args.in_amount,
swap_type=args.swap_type,
slippage=args.slippage,
)
print_trade_response(result, "Quote retrieved (dry-run - no actual trade)")
def cmd_chain_swap(args):
result = chain_swap(
chain=args.chain,
in_token=args.in_token,
out_token=args.out_token,
in_amount=args.in_amount,
swap_type=args.swap_type,
slippage=args.slippage,
recipient=args.recipient,
)
print_trade_response(result, "Swap executed!")
def cmd_proxy_quote(args):
result = proxy_quote(
chain=args.chain,
proxy_wallet=args.proxy_wallet,
in_token=args.in_token,
out_token=args.out_token,
in_amount=args.in_amount,
swap_type=args.swap_type,
)
print_trade_response(result, "Quote retrieved (dry-run - no actual trade)")
def cmd_proxy_market(args):
result = proxy_market_order(
chain=args.chain,
proxy_wallet=args.proxy_wallet,
in_token=args.in_token,
out_token=args.out_token,
in_amount=args.in_amount,
swap_type=args.swap_type,
tp_price=args.tp_price,
sl_price=args.sl_price,
)
print_trade_response(result, "Market order submitted!")
def cmd_proxy_limit(args):
result = proxy_limit_order(
chain=args.chain,
proxy_wallet=args.proxy_wallet,
in_token=args.in_token,
out_token=args.out_token,
in_amount=args.in_amount,
swap_type=args.swap_type,
price=args.price,
tp_price=args.tp_price,
sl_price=args.sl_price,
)
print_trade_response(result, "Limit order submitted!")
def cmd_proxy_cancel(args):
result = proxy_cancel_order(args.chain, args.order_id)
print_trade_response(result, "Order cancelled!")
def cmd_proxy_orders(args):
result = proxy_get_orders(args.chain, args.proxy_wallet, args.order_type)
print_trade_response(result)
def cmd_proxy_history(args):
result = proxy_get_order_history(args.chain, args.proxy_wallet)
print_trade_response(result)
def cmd_create_proxy_wallet(args):
result = create_proxy_wallet(args.chain)
print_trade_response(result, "Proxy wallet created!")
def cmd_list_proxy_wallets(args):
result = list_proxy_wallets(args.chain)
print_trade_response(result)
def main():
parser = argparse.ArgumentParser(description="AVE Cloud Trading REST API")
parser.add_argument(
"--api-key", default=API_KEY, help="AVE API key (or set AVE_API_KEY env)"
)
parser.add_argument(
"--api-plan", default=API_PLAN, help="API plan (or set API_PLAN env)"
)
parser.add_argument(
"--secret-key",
default=SECRET_KEY,
help="AVE SECRET_KEY for HMAC signing (or set AVE_SECRET_KEY env)",
)
subparsers = parser.add_subparsers(dest="command", help="Commands")
p_cquote = subparsers.add_parser(
"chain-quote", help="Chain wallet - get swap quote (dry-run)"
)
p_cquote.add_argument(
"--chain", required=True, help="Chain name (bsc, solana, eth, base)"
)
p_cquote.add_argument("--in-token", required=True, help="Input token address")
p_cquote.add_argument("--out-token", required=True, help="Output token address")
p_cquote.add_argument(
"--in-amount", required=True, help="Input amount (use string format)"
)
p_cquote.add_argument("--swap-type", required=True, help="Swap type (buy or sell)")
p_cquote.add_argument(
"--slippage", type=float, default=0.5, help="Slippage tolerance (default: 0.5)"
)
p_cswap = subparsers.add_parser("chain-swap", help="Chain wallet - execute swap")
p_cswap.add_argument("--chain", required=True, help="Chain name")
p_cswap.add_argument("--in-token", required=True, help="Input token address")
p_cswap.add_argument("--out-token", required=True, help="Output token address")
p_cswap.add_argument("--in-amount", required=True, help="Input amount")
p_cswap.add_argument("--swap-type", required=True, help="Swap type (buy or sell)")
p_cswap.add_argument(
"--slippage", type=float, default=0.5, help="Slippage tolerance"
)
p_cswap.add_argument("--recipient", help="Optional recipient address")
p_pquote = subparsers.add_parser(
"proxy-quote", help="Proxy wallet - get swap quote (dry-run)"
)
p_pquote.add_argument("--chain", required=True, help="Chain name")
p_pquote.add_argument("--proxy-wallet", required=True, help="Proxy wallet address")
p_pquote.add_argument("--in-token", required=True, help="Input token address")
p_pquote.add_argument("--out-token", required=True, help="Output token address")
p_pquote.add_argument("--in-amount", required=True, help="Input amount")
p_pquote.add_argument("--swap-type", required=True, help="Swap type (buy or sell)")
p_pmarket = subparsers.add_parser(
"proxy-market", help="Proxy wallet - submit market order"
)
p_pmarket.add_argument("--chain", required=True, help="Chain name")
p_pmarket.add_argument("--proxy-wallet", required=True, help="Proxy wallet address")
p_pmarket.add_argument("--in-token", required=True, help="Input token address")
p_pmarket.add_argument("--out-token", required=True, help="Output token address")
p_pmarket.add_argument("--in-amount", required=True, help="Input amount")
p_pmarket.add_argument("--swap-type", required=True, help="Swap type (buy or sell)")
p_pmarket.add_argument("--tp-price", help="Take-profit price")
p_pmarket.add_argument("--sl-price", help="Stop-loss price")
p_plimit = subparsers.add_parser(
"proxy-limit", help="Proxy wallet - submit limit order"
)
p_plimit.add_argument("--chain", required=True, help="Chain name")
p_plimit.add_argument("--proxy-wallet", required=True, help="Proxy wallet address")
p_plimit.add_argument("--in-token", required=True, help="Input token address")
p_plimit.add_argument("--out-token", required=True, help="Output token address")
p_plimit.add_argument("--in-amount", required=True, help="Input amount")
p_plimit.add_argument("--swap-type", required=True, help="Swap type (buy or sell)")
p_plimit.add_argument("--price", required=True, help="Limit price")
p_plimit.add_argument("--tp-price", help="Take-profit price")
p_plimit.add_argument("--sl-price", help="Stop-loss price")
p_cancel = subparsers.add_parser("proxy-cancel", help="Proxy wallet - cancel order")
p_cancel.add_argument("--chain", required=True, help="Chain name")
p_cancel.add_argument("--order-id", required=True, help="Order ID to cancel")
p_orders = subparsers.add_parser(
"proxy-orders", help="Proxy wallet - get open orders"
)
p_orders.add_argument("--chain", required=True, help="Chain name")
p_orders.add_argument("--proxy-wallet", required=True, help="Proxy wallet address")
p_orders.add_argument("--order-type", help="Filter by order type (market/limit)")
p_history = subparsers.add_parser(
"proxy-history", help="Proxy wallet - get order history"
)
p_history.add_argument("--chain", required=True, help="Chain name")
p_history.add_argument("--proxy-wallet", required=True, help="Proxy wallet address")
p_create = subparsers.add_parser(
"create-proxy-wallet", help="Create a new proxy wallet"
)
p_create.add_argument("--chain", required=True, help="Chain name")
p_list = subparsers.add_parser("list-proxy-wallets", help="List proxy wallets")
p_list.add_argument("--chain", required=True, help="Chain name")
args = parser.parse_args()
if not args.api_key:
print("Error: API key required. Set AVE_API_KEY env or use --api-key")
sys.exit(1)
if not args.command:
parser.print_help()
sys.exit(1)
cmd_map = {
"chain-quote": cmd_chain_quote,
"chain-swap": cmd_chain_swap,
"proxy-quote": cmd_proxy_quote,
"proxy-market": cmd_proxy_market,
"proxy-limit": cmd_proxy_limit,
"proxy-cancel": cmd_proxy_cancel,
"proxy-orders": cmd_proxy_orders,
"proxy-history": cmd_proxy_history,
"create-proxy-wallet": cmd_create_proxy_wallet,
"list-proxy-wallets": cmd_list_proxy_wallets,
}
cmd_map[args.command](args)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,2 @@
requests>=2.31.0
websocket-client>=1.7.0