Install
openclaw skills install @superior-ai/aerodromeUse 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.
openclaw skills install @superior-ai/aerodromeUse 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.
https://api.superior.tradex-api-key: $SUPERIOR_TRADE_API_KEYhttps://mainnet.base.orgWhen behavior is unclear, inspect these local sources before answering:
https://api.superior.tradeexchange.name: "aerodrome".AERO/USDC and CHECK/USDC. Never use :USDC.trading_mode, or set it to "spot" only.margin_mode, leverage, short entries, or futures fields.entry_pricing.use_order_book: false and exit_pricing.use_order_book: false.self.dp.orderbook(), fetch_order_book, fetch_l2_order_book, or order-book depth checks in strategy code.stake_amount. Avoid "unlimited" unless the user explicitly accepts balance exhaustion risk.https://mainnet.base.org for exchange.ccxt_config.options.rpcUrl unless the user explicitly provides another Base RPC.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:
AERO/USDC.stake_amount * max_open_trades below free quote balance and leave room for AMM slippage, token fees, and gas. Prefer 70-90% of available quote balance, lower for small wallets.Important distinction: Aerodrome uses Base wallet balances directly for on-chain swaps. Do not apply external exchange account rules here.
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.
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_currency must appear in the configured markets. For AERO/USDC, use USDC.trading_min_order_amount only when the strategy needs an explicit minimum; the API pads Aerodrome configs to 1 when omitted.dry_run, initial_state, api_server, walletAddress, privateKey, wallet_address, or private_key.ccxt_async_config is usually unnecessary for Aerodrome authoring unless current API tests show otherwise.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:
populate_indicators, populate_entry_trend, and populate_exit_trend.enter_long and exit_long only. Do not use enter_short.BBANDS, MACD, or STOCH, assign their returned columns explicitly.GET https://api.superior.trade/v2/backtesting-data/aerodrome?pair=AERO/USDC&timeframe=5m.POST https://api.superior.trade/v2/backtesting using { "config": {}, "code": "...", "timerange": { "start": "YYYY-MM-DD", "end": "YYYY-MM-DD" } }.PUT https://api.superior.trade/v2/backtesting/{id}/status and { "action": "start" }.GET https://api.superior.trade/v2/backtesting/{id}/status until completed or failed.GET https://api.superior.trade/v2/backtesting/{id} and inspect result_url for full metrics.Do not offer live deployment after a zero-trade backtest unless the user explicitly wants to debug live behavior.
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.
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.
POST https://api.superior.trade/v2/deployment using Aerodrome config and strategy code.POST https://api.superior.trade/v2/deployment/{id}/credentials with {"exchange":"aerodrome"}.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.PATCH https://api.superior.trade/v2/deployment/{id}/status and { "action": "start" }.GET https://api.superior.trade/v2/deployment/{id}/status and GET https://api.superior.trade/v2/deployment/{id}/logs.PATCH https://api.superior.trade/v2/deployment/{id}/status and { "action": "stop" }.margin_mode, leverage, shorting, or :USDC pair suffix.entry_pricing.use_order_book and exit_pricing.use_order_book are false.stake_amount is numeric and fits wallet balances with gas/slippage buffer.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)
trading_mode: "futures", trading_mode: "margin", and margin_mode.stake_currency with the quote or base token in exchange.ccxt_config.options.markets.use_order_book, order_book_top, depth checks, and strategy calls to self.dp.orderbook().stake_amount, data availability, and overly restrictive entry conditions.