moonpay-trading-automation
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTrading automation
交易自动化
Goal
目标
Compose CLI commands with OS scheduling (cron/launchd) to run unattended trading strategies: dollar-cost averaging, limit orders, and stop losses. The agent generates shell scripts and schedules them — no new tools needed.
mp通过组合 CLI命令与系统调度工具(cron/launchd),运行无人值守的交易策略:美元成本平均(DCA)、限价单和止损单。该工具会生成Shell脚本并进行调度——无需使用新工具。
mpPrerequisites
前提条件
- Authenticated:
mp user retrieve - Funded wallet:
mp token balance list --wallet <name> --chain <chain> - binary on PATH:
mp(note the full path for scheduled scripts)which mp - installed:
jqwhich jq
- 已完成身份验证:
mp user retrieve - 钱包已充值:
mp token balance list --wallet <name> --chain <chain> - 二进制文件已在PATH中:
mp(请记录完整路径,用于调度脚本)which mp - 已安装:
jqwhich jq
Shell script pattern
Shell脚本模板
Every strategy uses the same base pattern. Scripts live in and log to .
~/.config/moonpay/scripts/~/.config/moonpay/logs/trading.logbash
#!/bin/bash
set -euo pipefail
MP="$(which mp)" # absolute path for cron/launchd
LOG="$HOME/.config/moonpay/logs/trading.log"
mkdir -p "$(dirname "$LOG")"
log() { echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*" >> "$LOG"; }每种策略都使用相同的基础模板。脚本存储在目录下,日志输出到。
~/.config/moonpay/scripts/~/.config/moonpay/logs/trading.logbash
#!/bin/bash
set -euo pipefail
MP="$(which mp)" # absolute path for cron/launchd
LOG="$HOME/.config/moonpay/logs/trading.log"
mkdir -p "$(dirname "$LOG")"
log() { echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*" >> "$LOG"; }--- Config (agent fills these in) ---
--- Config (agent fills these in) ---
WALLET="main"
CHAIN="solana"
FROM_TOKEN="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" # USDC
TO_TOKEN="So11111111111111111111111111111111111111111" # SOL
AMOUNT=5
WALLET="main"
CHAIN="solana"
FROM_TOKEN="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" # USDC
TO_TOKEN="So11111111111111111111111111111111111111111" # SOL
AMOUNT=5
--- Execute ---
--- Execute ---
log "SWAP: $AMOUNT $FROM_TOKEN -> $TO_TOKEN on $CHAIN"
RESULT=$("$MP" -f compact token swap
--wallet "$WALLET" --chain "$CHAIN"
--from-token "$FROM_TOKEN" --from-amount "$AMOUNT"
--to-token "$TO_TOKEN" 2>&1) || { log "FAILED: $RESULT" exit 1 } log "OK: $RESULT"
--wallet "$WALLET" --chain "$CHAIN"
--from-token "$FROM_TOKEN" --from-amount "$AMOUNT"
--to-token "$TO_TOKEN" 2>&1) || { log "FAILED: $RESULT" exit 1 } log "OK: $RESULT"
Key points:
- `mp -f compact` outputs single-line JSON, ideal for `jq` parsing
- Use `$(which mp)` and store as `MP` — cron/launchd have minimal PATH
- Wallet names only in scripts — `mp` handles keychain decryption at runtime
- If the user gives token names/symbols, resolve to addresses first with `mp token search`log "SWAP: $AMOUNT $FROM_TOKEN -> $TO_TOKEN on $CHAIN"
RESULT=$("$MP" -f compact token swap
--wallet "$WALLET" --chain "$CHAIN"
--from-token "$FROM_TOKEN" --from-amount "$AMOUNT"
--to-token "$TO_TOKEN" 2>&1) || { log "FAILED: $RESULT" exit 1 } log "OK: $RESULT"
--wallet "$WALLET" --chain "$CHAIN"
--from-token "$FROM_TOKEN" --from-amount "$AMOUNT"
--to-token "$TO_TOKEN" 2>&1) || { log "FAILED: $RESULT" exit 1 } log "OK: $RESULT"
关键要点:
- `mp -f compact`输出单行JSON,非常适合`jq`解析
- 使用`$(which mp)`并将其存储为`MP`变量——cron/launchd的PATH环境变量非常有限
- 脚本中仅包含钱包名称——`mp`会在运行时通过钥匙串处理解密
- 如果用户提供的是代币名称/符号,请先使用`mp token search`解析为地址DCA (Dollar-Cost Averaging)
美元成本平均(DCA)
"Buy $5 of SOL every day at 9am"
"每天上午9点买入5美元的SOL"
Script: ~/.config/moonpay/scripts/dca-sol.sh
~/.config/moonpay/scripts/dca-sol.sh脚本:~/.config/moonpay/scripts/dca-sol.sh
~/.config/moonpay/scripts/dca-sol.shUse the base pattern above with the user's token, amount, wallet, and chain.
使用上述基础模板,填入用户的代币、金额、钱包和链信息。
Schedule with cron (Linux)
使用cron调度(Linux)
bash
undefinedbash
undefinedBuy $5 of SOL daily at 9am UTC — moonpay:dca-sol
Buy $5 of SOL daily at 9am UTC — moonpay:dca-sol
0 9 * * * ~/.config/moonpay/scripts/dca-sol.sh
Add with: `(crontab -l 2>/dev/null; echo '0 9 * * * ~/.config/moonpay/scripts/dca-sol.sh # moonpay:dca-sol') | crontab -`
Common intervals:
- Every hour: `0 * * * *`
- Every 4 hours: `0 */4 * * *`
- Daily at 9am: `0 9 * * *`
- Weekly Monday 9am: `0 9 * * 1`0 9 * * * ~/.config/moonpay/scripts/dca-sol.sh
添加方式:`(crontab -l 2>/dev/null; echo '0 9 * * * ~/.config/moonpay/scripts/dca-sol.sh # moonpay:dca-sol') | crontab -`
常见时间间隔:
- 每小时:`0 * * * *`
- 每4小时:`0 */4 * * *`
- 每天上午9点:`0 9 * * *`
- 每周一上午9点:`0 9 * * 1`Schedule with launchd (macOS)
使用launchd调度(macOS)
Write a plist to :
~/Library/LaunchAgents/com.moonpay.dca-sol.plistxml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.moonpay.dca-sol</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/Users/USERNAME/.config/moonpay/scripts/dca-sol.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>9</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardErrorPath</key>
<string>/Users/USERNAME/.config/moonpay/logs/dca-sol.err</string>
</dict>
</plist>Load with:
launchctl load ~/Library/LaunchAgents/com.moonpay.dca-sol.plistImportant: Tilde () does NOT expand in plist files. Always use the full path (e.g., ). Get it with .
~/Users/USERNAME/...echo $HOME将plist文件写入:
~/Library/LaunchAgents/com.moonpay.dca-sol.plistxml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.moonpay.dca-sol</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/Users/USERNAME/.config/moonpay/scripts/dca-sol.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>9</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardErrorPath</key>
<string>/Users/USERNAME/.config/moonpay/logs/dca-sol.err</string>
</dict>
</plist>加载方式:
launchctl load ~/Library/LaunchAgents/com.moonpay.dca-sol.plist重要提示: plist文件中不会展开波浪号()。请始终使用完整路径(例如)。可通过获取完整路径。
~/Users/USERNAME/...echo $HOMELimit order
限价单
"Buy SOL when price drops below $80"
"当SOL价格跌至80美元以下时买入"
Script: ~/.config/moonpay/scripts/limit-buy-sol.sh
~/.config/moonpay/scripts/limit-buy-sol.sh脚本:~/.config/moonpay/scripts/limit-buy-sol.sh
~/.config/moonpay/scripts/limit-buy-sol.shbash
#!/bin/bash
set -euo pipefail
MP="$(which mp)"
LOG="$HOME/.config/moonpay/logs/trading.log"
mkdir -p "$(dirname "$LOG")"
log() { echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*" >> "$LOG"; }bash
#!/bin/bash
set -euo pipefail
MP="$(which mp)"
LOG="$HOME/.config/moonpay/logs/trading.log"
mkdir -p "$(dirname "$LOG")"
log() { echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*" >> "$LOG"; }--- Config ---
--- Config ---
WALLET="main"
CHAIN="solana"
TOKEN="So11111111111111111111111111111111111111111"
BUY_WITH="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" # USDC
BUY_AMOUNT=50
TARGET_PRICE=80
SCRIPT_NAME="limit-buy-sol"
WALLET="main"
CHAIN="solana"
TOKEN="So11111111111111111111111111111111111111111"
BUY_WITH="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" # USDC
BUY_AMOUNT=50
TARGET_PRICE=80
SCRIPT_NAME="limit-buy-sol"
--- Check price ---
--- Check price ---
PRICE=$("$MP" -f compact token retrieve --token "$TOKEN" --chain "$CHAIN" | jq -r '.marketData.price')
if [ -z "$PRICE" ] || [ "$PRICE" = "null" ]; then
log "LIMIT $SCRIPT_NAME: price fetch failed, skipping"
exit 0
fi
PRICE=$("$MP" -f compact token retrieve --token "$TOKEN" --chain "$CHAIN" | jq -r '.marketData.price')
if [ -z "$PRICE" ] || [ "$PRICE" = "null" ]; then
log "LIMIT $SCRIPT_NAME: price fetch failed, skipping"
exit 0
fi
--- Compare ---
--- Compare ---
if (( $(echo "$PRICE < $TARGET_PRICE" | bc -l) )); then
log "LIMIT $SCRIPT_NAME: price $PRICE < $TARGET_PRICE — executing buy"
RESULT=$("$MP" -f compact token swap
--wallet "$WALLET" --chain "$CHAIN"
--from-token "$BUY_WITH" --from-amount "$BUY_AMOUNT"
--to-token "$TOKEN" 2>&1) || { log "LIMIT $SCRIPT_NAME FAILED: $RESULT" exit 1 } log "LIMIT $SCRIPT_NAME OK: bought at $PRICE — $RESULT"
--wallet "$WALLET" --chain "$CHAIN"
--from-token "$BUY_WITH" --from-amount "$BUY_AMOUNT"
--to-token "$TOKEN" 2>&1) || { log "LIMIT $SCRIPT_NAME FAILED: $RESULT" exit 1 } log "LIMIT $SCRIPT_NAME OK: bought at $PRICE — $RESULT"
Self-disable after fill
if [[ "$OSTYPE" == "darwin"* ]]; then
launchctl unload "$HOME/Library/LaunchAgents/com.moonpay.${SCRIPT_NAME}.plist" 2>/dev/null || true
else
crontab -l | grep -v "$SCRIPT_NAME" | crontab -
fi
log "LIMIT $SCRIPT_NAME: disabled after fill"
else
log "LIMIT $SCRIPT_NAME: price $PRICE >= $TARGET_PRICE — waiting"
fi
Schedule every 5 minutes:
- Cron: `*/5 * * * * ~/.config/moonpay/scripts/limit-buy-sol.sh # moonpay:limit-buy-sol`
- Launchd: use `<key>StartInterval</key><integer>300</integer>` instead of `StartCalendarInterval`if (( $(echo "$PRICE < $TARGET_PRICE" | bc -l) )); then
log "LIMIT $SCRIPT_NAME: price $PRICE < $TARGET_PRICE — executing buy"
RESULT=$("$MP" -f compact token swap
--wallet "$WALLET" --chain "$CHAIN"
--from-token "$BUY_WITH" --from-amount "$BUY_AMOUNT"
--to-token "$TOKEN" 2>&1) || { log "LIMIT $SCRIPT_NAME FAILED: $RESULT" exit 1 } log "LIMIT $SCRIPT_NAME OK: bought at $PRICE — $RESULT"
--wallet "$WALLET" --chain "$CHAIN"
--from-token "$BUY_WITH" --from-amount "$BUY_AMOUNT"
--to-token "$TOKEN" 2>&1) || { log "LIMIT $SCRIPT_NAME FAILED: $RESULT" exit 1 } log "LIMIT $SCRIPT_NAME OK: bought at $PRICE — $RESULT"
Self-disable after fill
if [[ "$OSTYPE" == "darwin"* ]]; then
launchctl unload "$HOME/Library/LaunchAgents/com.moonpay.${SCRIPT_NAME}.plist" 2>/dev/null || true
else
crontab -l | grep -v "$SCRIPT_NAME" | crontab -
fi
log "LIMIT $SCRIPT_NAME: disabled after fill"
else
log "LIMIT $SCRIPT_NAME: price $PRICE >= $TARGET_PRICE — waiting"
fi
设置为每5分钟调度一次:
- Cron:`*/5 * * * * ~/.config/moonpay/scripts/limit-buy-sol.sh # moonpay:limit-buy-sol`
- Launchd:使用`<key>StartInterval</key><integer>300</integer>`替代`StartCalendarInterval`Stop loss
止损单
"Sell all my SOL if price drops below $70"
Same structure as limit order but sells instead of buys. For "sell all", query the balance first:
bash
undefined"当SOL价格跌至70美元以下时卖出所有持仓"
结构与限价单相同,但改为卖出而非买入。对于“卖出所有”操作,请先查询当前余额:
bash
undefined--- Config ---
--- Config ---
SELL_TOKEN="So11111111111111111111111111111111111111111" # SOL
TO_TOKEN="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" # USDC
TRIGGER_PRICE=70
SCRIPT_NAME="stop-loss-sol"
SELL_TOKEN="So11111111111111111111111111111111111111111" # SOL
TO_TOKEN="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" # USDC
TRIGGER_PRICE=70
SCRIPT_NAME="stop-loss-sol"
--- Check price ---
--- Check price ---
PRICE=$("$MP" -f compact token retrieve --token "$SELL_TOKEN" --chain "$CHAIN" | jq -r '.marketData.price')
if (( $(echo "$PRICE < $TRIGGER_PRICE" | bc -l) )); then
Get current balance to sell all
BALANCE=$("$MP" -f compact token balance list --wallet "$WALLET" --chain "$CHAIN"
| jq -r --arg addr "$SELL_TOKEN" '.items[] | select(.address == $addr) | .balance.amount')
| jq -r --arg addr "$SELL_TOKEN" '.items[] | select(.address == $addr) | .balance.amount')
if [ -n "$BALANCE" ] && (( $(echo "$BALANCE > 0" | bc -l) )); then
log "STOP-LOSS $SCRIPT_NAME: price $PRICE < $TRIGGER_PRICE — selling $BALANCE"
RESULT=$("$MP" -f compact token swap
--wallet "$WALLET" --chain "$CHAIN"
--from-token "$SELL_TOKEN" --from-amount "$BALANCE"
--to-token "$TO_TOKEN" 2>&1) || { log "STOP-LOSS $SCRIPT_NAME FAILED: $RESULT" exit 1 } log "STOP-LOSS $SCRIPT_NAME OK: sold at $PRICE — $RESULT" # Self-disable (same pattern as limit order) fi fi
--wallet "$WALLET" --chain "$CHAIN"
--from-token "$SELL_TOKEN" --from-amount "$BALANCE"
--to-token "$TO_TOKEN" 2>&1) || { log "STOP-LOSS $SCRIPT_NAME FAILED: $RESULT" exit 1 } log "STOP-LOSS $SCRIPT_NAME OK: sold at $PRICE — $RESULT" # Self-disable (same pattern as limit order) fi fi
undefinedPRICE=$("$MP" -f compact token retrieve --token "$SELL_TOKEN" --chain "$CHAIN" | jq -r '.marketData.price')
if (( $(echo "$PRICE < $TRIGGER_PRICE" | bc -l) )); then
Get current balance to sell all
BALANCE=$("$MP" -f compact token balance list --wallet "$WALLET" --chain "$CHAIN"
| jq -r --arg addr "$SELL_TOKEN" '.items[] | select(.address == $addr) | .balance.amount')
| jq -r --arg addr "$SELL_TOKEN" '.items[] | select(.address == $addr) | .balance.amount')
if [ -n "$BALANCE" ] && (( $(echo "$BALANCE > 0" | bc -l) )); then
log "STOP-LOSS $SCRIPT_NAME: price $PRICE < $TRIGGER_PRICE — selling $BALANCE"
RESULT=$("$MP" -f compact token swap
--wallet "$WALLET" --chain "$CHAIN"
--from-token "$SELL_TOKEN" --from-amount "$BALANCE"
--to-token "$TO_TOKEN" 2>&1) || { log "STOP-LOSS $SCRIPT_NAME FAILED: $RESULT" exit 1 } log "STOP-LOSS $SCRIPT_NAME OK: sold at $PRICE — $RESULT" # Self-disable (same pattern as limit order) fi fi
--wallet "$WALLET" --chain "$CHAIN"
--from-token "$SELL_TOKEN" --from-amount "$BALANCE"
--to-token "$TO_TOKEN" 2>&1) || { log "STOP-LOSS $SCRIPT_NAME FAILED: $RESULT" exit 1 } log "STOP-LOSS $SCRIPT_NAME OK: sold at $PRICE — $RESULT" # Self-disable (same pattern as limit order) fi fi
undefinedManaging automations
自动化管理
List active automations
查看已激活的自动化任务
bash
undefinedbash
undefinedmacOS
macOS
launchctl list | grep moonpay
launchctl list | grep moonpay
Linux
Linux
crontab -l | grep moonpay
undefinedcrontab -l | grep moonpay
undefinedRemove an automation
删除自动化任务
bash
undefinedbash
undefinedmacOS
macOS
launchctl unload ~/Library/LaunchAgents/com.moonpay.dca-sol.plist
rm ~/Library/LaunchAgents/com.moonpay.dca-sol.plist
launchctl unload ~/Library/LaunchAgents/com.moonpay.dca-sol.plist
rm ~/Library/LaunchAgents/com.moonpay.dca-sol.plist
Linux
Linux
crontab -l | grep -v "moonpay:dca-sol" | crontab -
undefinedcrontab -l | grep -v "moonpay:dca-sol" | crontab -
undefinedView logs
查看日志
bash
tail -50 ~/.config/moonpay/logs/trading.logbash
tail -50 ~/.config/moonpay/logs/trading.logPause / resume (macOS only)
暂停 / 恢复(仅macOS)
bash
launchctl unload ~/Library/LaunchAgents/com.moonpay.dca-sol.plist # pause
launchctl load ~/Library/LaunchAgents/com.moonpay.dca-sol.plist # resumebash
launchctl unload ~/Library/LaunchAgents/com.moonpay.dca-sol.plist # 暂停
launchctl load ~/Library/LaunchAgents/com.moonpay.dca-sol.plist # 恢复Platform detection
平台检测
Detect the OS and use the appropriate scheduler:
bash
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS: use launchd (fires even if machine was asleep)
else
# Linux: use crontab
fi检测操作系统并使用对应的调度工具:
bash
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS: use launchd (fires even if machine was asleep)
else
# Linux: use crontab
fiTips
提示
- Start with a small DCA amount to verify the setup works before going bigger
- Check logs after the first run:
tail -20 ~/.config/moonpay/logs/trading.log - Scripts don't contain secrets — decrypts wallets via OS keychain at runtime
mp - The machine must be logged in (user session active) for keychain access to work
- Price checks via are free; swaps cost gas
mp token retrieve - Limit order checks every 5 minutes is reasonable — don't go below 1 minute
- Use for decimal price comparison (bash can't compare floats natively)
bc -l - If isn't available, use:
bcawk "BEGIN {exit !($PRICE < $TARGET)}" - Always tag cron entries with so they can be found and removed
# moonpay:{name}
- 先使用小额DCA金额验证设置是否正常,再逐步加大金额
- 首次运行后查看日志:
tail -20 ~/.config/moonpay/logs/trading.log - 脚本不包含敏感信息——会在运行时通过系统钥匙串解密钱包
mp - 机器必须处于登录状态(用户会话激活)才能访问钥匙串
- 通过查询价格是免费的;交易操作需要支付Gas费
mp token retrieve - 限价单每5分钟检查一次较为合理——不要低于1分钟
- 使用进行小数价格比较(bash原生不支持浮点数比较)
bc -l - 如果未安装,可使用:
bcawk "BEGIN {exit !($PRICE < $TARGET)}" - 请始终为cron任务添加标签,以便查找和删除
# moonpay:{name}
Related skills
相关技能
- moonpay-swap-tokens — Swap and bridge command syntax
- moonpay-check-wallet — Check balances before setting up automation
- moonpay-discover-tokens — Research tokens and resolve addresses
- moonpay-price-alerts — Observe-only price notifications (no trading)
- moonpay-swap-tokens — 代币兑换与跨链桥接命令语法
- moonpay-check-wallet — 设置自动化前检查钱包余额
- moonpay-discover-tokens — 研究代币并解析地址
- moonpay-price-alerts — 仅查看价格通知(不执行交易)