Aerodrome
Skill Superior-Trade/superior-skills/skills/v2/exchanges/aerodrome
Open agent skills and tool schemas for Superior Trade — build, backtest, and deploy trading strategies on Hyperliquid
npx -y skills add Superior-Trade/superior-skills --skill aerodromeAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Use when creating, validating, backtesting, deploying, sizing, or troubleshooting Aerodrome/Base spot trading strategies through the Superior Trade API, especially Freqtrade configs using exchange.name "aerodrome", AERO/USDC or CHECK/USDC pairs, AMM market swaps, wallet/gas balance checks, no-orderbook pricing, or Aerodrome live deployment safety.
SKILL.md
16.4 KB, as published. Nobody here has run it
Aerodrome Trading
Overview
Use this skill only for Aerodrome trading on Base through Superior Trade. Aerodrome is spot-only AMM swap execution: no futures, no margin, no shorting, no leverage, no sub-accounts, and no order book.
Production Defaults
- Superior Trade API base URL:
https://api.superior.trade - Auth header:
x-api-key: $SUPERIOR_TRADE_API_KEY - Base RPC URL:
https://mainnet.base.org - Keep setup simple: one pair, one numeric stake amount, static pairlist, market orders, and no orderbook pricing.
Source Of Truth
When behavior is unclear, inspect these local sources before answering:
- Production API:
https://api.superior.trade
Non-Negotiables
- Use
exchange.name: "aerodrome". - Use only the supported spot pairs:
AERO/USDCandCHECK/USDC. Never use:USDC. - Omit
trading_mode, or set it to"spot"only. - Never set
margin_mode,leverage, short entries, or futures fields. - Set
entry_pricing.use_order_book: falseandexit_pricing.use_order_book: false. - Do not call
self.dp.orderbook(),fetch_order_book,fetch_l2_order_book, or order-book depth checks in strategy code. - Use market orders. Aerodrome's CCXT adapter supports AMM market swaps, not limit-order-book execution.
- Use explicit numeric
stake_amount. Avoid"unlimited"unless the user explicitly accepts balance exhaustion risk. - Never include wallet private keys or platform-injected exchange credentials in config.
- Use
https://mainnet.base.orgforexchange.ccxt_config.options.rpcUrlunless the user explicitly provides another Base RPC. - Always backtest before suggesting live deployment.
- Never start live trading without explicit user confirmation.
Wallet And Balance Rules
Aerodrome live trading depends heavily on the Base wallet balances because every order is an on-chain swap.
Before live deployment or when troubleshooting zero trades:
- Verify the wallet has enough quote token for buys, usually USDC.
- Verify it has enough base token for sells, such as AERO for
AERO/USDC. - Verify it has Base ETH for gas. A small ETH balance is required even when trading USDC pairs.
- Size
stake_amount * max_open_tradesbelow free quote balance and leave room for AMM slippage, token fees, and gas. Prefer 70-90% of available quote balance, lower for small wallets. - If the wallet balance cannot be checked in the current turn, say it has not been checked. Do not infer or fabricate balances.
Important distinction: Aerodrome uses Base wallet balances directly for on-chain swaps. Do not apply external exchange account rules here.
Supported Markets
Hard-code these Aerodrome/Base market definitions when configuring exchange.ccxt_config.options.markets:
| Symbol | Base address | Base decimals | Quote address | Quote decimals | Pool address | Stable |
|---|---|---|---|---|---|---|
AERO/USDC | 0x940181a94A35A4569E4529A3CDfB74e38FD98631 | 18 | 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 | 6 | 0x6cdcb1c4a4d1c3c6d054b27ac5b77e89eafb971d | false |
CHECK/USDC | 0x9126236476eFBA9Ad8aB77855c60eB5BF37586Eb | 18 | 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 | 6 | 0x6a4BeFa1337865071E27c62dc9d7E3bCa253cE0f | false |
Backtesting data is available for both supported pairs on 5m, 15m, 1h, 4h, and 1d.
Minimum Config
Start from this shape and only change pair_whitelist, timeframe, stake, and strategy parameters. Keep the hard-coded supported markets and no-orderbook fields.
{
"exchange": {
"name": "aerodrome",
"pair_whitelist": ["AERO/USDC"],
"ccxt_config": {
"options": {
"rpcUrl": "https://mainnet.base.org",
"markets": [
{
"symbol": "AERO/USDC",
"baseAddress": "0x940181a94A35A4569E4529A3CDfB74e38FD98631",
"baseDecimals": 18,
"quoteAddress": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"quoteDecimals": 6,
"poolAddress": "0x6cdcb1c4a4d1c3c6d054b27ac5b77e89eafb971d",
"stable": false
},
{
"symbol": "CHECK/USDC",
"baseAddress": "0x9126236476eFBA9Ad8aB77855c60eB5BF37586Eb",
"baseDecimals": 18,
"quoteAddress": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"quoteDecimals": 6,
"poolAddress": "0x6a4BeFa1337865071E27c62dc9d7E3bCa253cE0f",
"stable": false
}
]
}
}
},
"stake_currency": "USDC",
"stake_amount": 10,
"max_open_trades": 1,
"timeframe": "5m",
"stoploss": -0.1,
"minimal_roi": { "0": 0.05 },
"order_types": {
"entry": "market",
"exit": "market",
"force_entry": "market",
"force_exit": "market",
"emergency_exit": "market",
"stoploss": "market",
"stoploss_on_exchange": false
},
"entry_pricing": { "price_side": "other", "use_order_book": false },
"exit_pricing": { "price_side": "other", "use_order_book": false },
"pairlists": [{ "method": "StaticPairList" }]
}
Notes:
stake_currencymust appear in the configured markets. ForAERO/USDC, useUSDC.- Use
trading_min_order_amountonly when the strategy needs an explicit minimum; the API pads Aerodrome configs to1when omitted. - Do not include
dry_run,initial_state,api_server,walletAddress,privateKey,wallet_address, orprivate_key. ccxt_async_configis usually unnecessary for Aerodrome authoring unless current API tests show otherwise.
Strategy Template
from freqtrade.strategy import IStrategy
import pandas as pd
import talib.abstract as ta
class AerodromeRsiStrategy(IStrategy):
timeframe = "5m"
process_only_new_candles = True
startup_candle_count = 50
minimal_roi = {"0": 0.05}
stoploss = -0.10
can_short = False
def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
dataframe["ema_50"] = ta.EMA(dataframe, timeperiod=50)
return dataframe
def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
dataframe.loc[
(dataframe["volume"] > 0)
& (dataframe["rsi"] < 35)
& (dataframe["close"] > dataframe["ema_50"]),
"enter_long",
] = 1
return dataframe
def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
dataframe.loc[
(dataframe["rsi"] > 65),
"exit_long",
] = 1
return dataframe
Rules for generated strategy code:
- Implement
populate_indicators,populate_entry_trend, andpopulate_exit_trend. - Use
enter_longandexit_longonly. Do not useenter_short. - Do not do custom network calls from strategy hot paths.
- Do not rely on bid/ask spread, order-book imbalance, depth, or maker/taker limit placement.
- If using multi-output TA-Lib functions such as
BBANDS,MACD, orSTOCH, assign their returned columns explicitly.
Backtest Workflow
- Build Aerodrome config and Freqtrade strategy code.
- Check data availability with
GET https://api.superior.trade/v2/backtesting-data/aerodrome?pair=AERO/USDC&timeframe=5m. - Create a backtest with
POST https://api.superior.trade/v2/backtestingusing{ "config": {}, "code": "...", "timerange": { "start": "YYYY-MM-DD", "end": "YYYY-MM-DD" } }. - Start it with
PUT https://api.superior.trade/v2/backtesting/{id}/statusand{ "action": "start" }. - Poll
GET https://api.superior.trade/v2/backtesting/{id}/statusuntilcompletedorfailed. - Fetch
GET https://api.superior.trade/v2/backtesting/{id}and inspectresult_urlfor full metrics. - Present total trades, win rate, profit, drawdown, and whether results justify live testing.
Do not offer live deployment after a zero-trade backtest unless the user explicitly wants to debug live behavior.
Aerodrome API Quick Reference
Use SUPERIOR_TRADE_API_KEY from the environment. Do not paste API keys into commands, files, or logs.
Check data availability:
curl -sS --get "https://api.superior.trade/v2/backtesting-data/aerodrome" \
--data-urlencode "pair=AERO/USDC" \
--data-urlencode "timeframe=5m"
Expected success shape:
{
"available": true,
"pair": "AERO/USDC",
"timeframe": "5m",
"from": "ISO8601 when cataloged",
"to": "ISO8601 when cataloged",
"candles": 1234
}
If available is false or the response says data will be fetched live from Bitquery, it is still acceptable to create the backtest unless the user requested only pre-downloaded data.
Create the backtest:
curl -sS -X POST "https://api.superior.trade/v2/backtesting" \
-H "content-type: application/json" \
-H "x-api-key: ${SUPERIOR_TRADE_API_KEY}" \
--data @aero-backtest.json
Create response:
{
"id": "string",
"status": "pending",
"message": "Backtest created. Call PUT /:id/status with action \"start\" to begin."
}
Start the backtest:
curl -sS -X PUT "https://api.superior.trade/v2/backtesting/${BACKTEST_ID}/status" \
-H "content-type: application/json" \
-H "x-api-key: ${SUPERIOR_TRADE_API_KEY}" \
--data '{"action":"start"}'
Poll status every 10 seconds until completed or failed:
curl -sS "https://api.superior.trade/v2/backtesting/${BACKTEST_ID}/status" \
-H "x-api-key: ${SUPERIOR_TRADE_API_KEY}"
Fetch full details after completion:
curl -sS "https://api.superior.trade/v2/backtesting/${BACKTEST_ID}" \
-H "x-api-key: ${SUPERIOR_TRADE_API_KEY}"
If failed, fetch logs:
curl -sS "https://api.superior.trade/v2/backtesting/${BACKTEST_ID}/logs?pageSize=100" \
-H "x-api-key: ${SUPERIOR_TRADE_API_KEY}"
Cancel or delete a backtest:
curl -sS -X DELETE "https://api.superior.trade/v2/backtesting/${BACKTEST_ID}" \
-H "x-api-key: ${SUPERIOR_TRADE_API_KEY}"
Status responses may include parsed results. Full details may include a signed resultUrl; download it for full Freqtrade metrics when present. Present at least total trades, win rate, total profit, max drawdown, and Sharpe ratio. If a backtest fails, summarize the relevant log lines and the likely fix.
AERO/USDC Backtest Payload
Use this as the default aero-backtest.json for a simple AERO strategy unless the user requested different risk, timeframe, timerange, or indicators.
{
"config": {
"exchange": {
"name": "aerodrome",
"pair_whitelist": ["AERO/USDC"],
"ccxt_config": {
"options": {
"rpcUrl": "https://mainnet.base.org",
"markets": [
{
"symbol": "AERO/USDC",
"baseAddress": "0x940181a94A35A4569E4529A3CDfB74e38FD98631",
"baseDecimals": 18,
"quoteAddress": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"quoteDecimals": 6,
"poolAddress": "0x6cdcb1c4a4d1c3c6d054b27ac5b77e89eafb971d",
"stable": false
},
{
"symbol": "CHECK/USDC",
"baseAddress": "0x9126236476eFBA9Ad8aB77855c60eB5BF37586Eb",
"baseDecimals": 18,
"quoteAddress": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"quoteDecimals": 6,
"poolAddress": "0x6a4BeFa1337865071E27c62dc9d7E3bCa253cE0f",
"stable": false
}
]
}
}
},
"stake_currency": "USDC",
"stake_amount": 10,
"max_open_trades": 1,
"timeframe": "5m",
"stoploss": -0.1,
"minimal_roi": { "0": 0.05 },
"order_types": {
"entry": "market",
"exit": "market",
"force_entry": "market",
"force_exit": "market",
"emergency_exit": "market",
"stoploss": "market",
"stoploss_on_exchange": false
},
"entry_pricing": { "price_side": "other", "use_order_book": false },
"exit_pricing": { "price_side": "other", "use_order_book": false },
"pairlists": [{ "method": "StaticPairList" }]
},
"code": "from freqtrade.strategy import IStrategy\nimport pandas as pd\nimport talib.abstract as ta\n\n\nclass AeroRsiEmaStrategy(IStrategy):\n timeframe = \"5m\"\n process_only_new_candles = True\n startup_candle_count = 50\n minimal_roi = {\"0\": 0.05}\n stoploss = -0.10\n can_short = False\n\n def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:\n dataframe[\"rsi\"] = ta.RSI(dataframe, timeperiod=14)\n dataframe[\"ema_50\"] = ta.EMA(dataframe, timeperiod=50)\n return dataframe\n\n def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:\n dataframe.loc[\n (dataframe[\"volume\"] > 0)\n & (dataframe[\"rsi\"] < 35)\n & (dataframe[\"close\"] > dataframe[\"ema_50\"]),\n \"enter_long\",\n ] = 1\n return dataframe\n\n def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:\n dataframe.loc[\n (dataframe[\"rsi\"] > 65),\n \"exit_long\",\n ] = 1\n return dataframe\n",
"timerange": {
"start": "2026-03-01",
"end": "2026-04-01"
}
}
Before submitting a modified payload, re-check it against the non-negotiables: spot-only, no :USDC pair suffix, no private keys, no orderbook pricing, market order types, numeric stake amount, and supported Aerodrome market metadata.
Live Deployment Workflow
- Create deployment with
POST https://api.superior.trade/v2/deploymentusing Aerodrome config and strategy code. - Store or confirm credentials using the current API behavior:
- Prefer the documented v2 flow when supported:
POST https://api.superior.trade/v2/deployment/{id}/credentialswith{"exchange":"aerodrome"}. - If the current API rejects Aerodrome on the v2 credentials route, inspect the local
api/src/routes/credentials-v2.ts,api/src/routes/deployment.ts, and OpenAPI before proceeding. Do not ask the user for private keys unless the live API explicitly requires that legacy flow.
- Prefer the documented v2 flow when supported:
- Run the pre-deployment checklist below.
- Show a concise live trading summary and wait for explicit confirmation.
- Start with
PATCH https://api.superior.trade/v2/deployment/{id}/statusand{ "action": "start" }. - Monitor status and logs with
GET https://api.superior.trade/v2/deployment/{id}/statusandGET https://api.superior.trade/v2/deployment/{id}/logs. - Stop with
PATCH https://api.superior.trade/v2/deployment/{id}/statusand{ "action": "stop" }.
Pre-Deployment Checklist
- Backtest completed and was reviewed.
- Config is Aerodrome spot-only and has no
margin_mode, leverage, shorting, or:USDCpair suffix. entry_pricing.use_order_bookandexit_pricing.use_order_bookare false.stake_amountis numeric and fits wallet balances with gas/slippage buffer.- Wallet has Base ETH for gas and enough relevant token balance for intended buys/sells.
- Strategy has no custom orderbook or RPC polling.
- User explicitly confirmed live trading.
Use this confirmation format:
Deployment Summary:
- Exchange: aerodrome on Base
- Trading mode: spot only
- Pair: [pair]
- Stake amount: [amount] [stake_currency] per trade
- Max open trades: [n]
- Stoploss: [percentage]
- Order execution: AMM market swaps, no orderbook
- Wallet balance checked: [yes/no, source]
- Base ETH gas checked: [yes/no, source]
This will trade with real funds. Proceed? (yes/no)
Troubleshooting
- Validation says Aerodrome only supports spot: remove
trading_mode: "futures",trading_mode: "margin", andmargin_mode. - Validation says stake currency is not present in markets: align
stake_currencywith the quote or base token inexchange.ccxt_config.options.markets. - Orderbook errors: remove
use_order_book,order_book_top, depth checks, and strategy calls toself.dp.orderbook(). - Zero trades: check wallet token balance, ETH gas, numeric
stake_amount, data availability, and overly restrictive entry conditions. - Market buy requires price: keep Freqtrade market order config and avoid hand-calling CCXT without price; Aerodrome market buys need price context for cost calculation.
- Aerodrome swaps are atomic, so stopping the bot does not need a position-close cleanup routine.