moonpay-trading-automation

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Trading automation

交易自动化

Goal

目标

Compose
mp
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脚本并进行调度——无需使用新工具。

Prerequisites

前提条件

  • Authenticated:
    mp user retrieve
  • Funded wallet:
    mp token balance list --wallet <name> --chain <chain>
  • mp
    binary on PATH:
    which mp
    (note the full path for scheduled scripts)
  • jq
    installed:
    which jq
  • 已完成身份验证:
    mp user retrieve
  • 钱包已充值:
    mp token balance list --wallet <name> --chain <chain>
  • mp
    二进制文件已在PATH中:
    which mp
    (请记录完整路径,用于调度脚本)
  • 已安装
    jq
    which jq

Shell script pattern

Shell脚本模板

Every strategy uses the same base pattern. Scripts live in
~/.config/moonpay/scripts/
and log to
~/.config/moonpay/logs/trading.log
.
bash
#!/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.log
bash
#!/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"

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"

关键要点:
- `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

Use the base pattern above with the user's token, amount, wallet, and chain.
使用上述基础模板,填入用户的代币、金额、钱包和链信息。

Schedule with cron (Linux)

使用cron调度(Linux)

bash
undefined
bash
undefined

Buy $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.plist
:
xml
<?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.plist
Important: Tilde (
~
) does NOT expand in plist files. Always use the full path (e.g.,
/Users/USERNAME/...
). Get it with
echo $HOME
.
将plist文件写入
~/Library/LaunchAgents/com.moonpay.dca-sol.plist
xml
<?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 $HOME
获取完整路径。

Limit 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

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"; }
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"

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"

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')
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
undefined
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')
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
undefined

Managing automations

自动化管理

List active automations

查看已激活的自动化任务

bash
undefined
bash
undefined

macOS

macOS

launchctl list | grep moonpay
launchctl list | grep moonpay

Linux

Linux

crontab -l | grep moonpay
undefined
crontab -l | grep moonpay
undefined

Remove an automation

删除自动化任务

bash
undefined
bash
undefined

macOS

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 -
undefined
crontab -l | grep -v "moonpay:dca-sol" | crontab -
undefined

View logs

查看日志

bash
tail -50 ~/.config/moonpay/logs/trading.log
bash
tail -50 ~/.config/moonpay/logs/trading.log

Pause / resume (macOS only)

暂停 / 恢复(仅macOS)

bash
launchctl unload ~/Library/LaunchAgents/com.moonpay.dca-sol.plist   # pause
launchctl load ~/Library/LaunchAgents/com.moonpay.dca-sol.plist     # resume
bash
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
fi

Tips

提示

  • 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 —
    mp
    decrypts wallets via OS keychain at runtime
  • The machine must be logged in (user session active) for keychain access to work
  • Price checks via
    mp token retrieve
    are free; swaps cost gas
  • Limit order checks every 5 minutes is reasonable — don't go below 1 minute
  • Use
    bc -l
    for decimal price comparison (bash can't compare floats natively)
  • If
    bc
    isn't available, use:
    awk "BEGIN {exit !($PRICE < $TARGET)}"
  • Always tag cron entries with
    # moonpay:{name}
    so they can be found and removed
  • 先使用小额DCA金额验证设置是否正常,再逐步加大金额
  • 首次运行后查看日志:
    tail -20 ~/.config/moonpay/logs/trading.log
  • 脚本不包含敏感信息——
    mp
    会在运行时通过系统钥匙串解密钱包
  • 机器必须处于登录状态(用户会话激活)才能访问钥匙串
  • 通过
    mp token retrieve
    查询价格是免费的;交易操作需要支付Gas费
  • 限价单每5分钟检查一次较为合理——不要低于1分钟
  • 使用
    bc -l
    进行小数价格比较(bash原生不支持浮点数比较)
  • 如果未安装
    bc
    ,可使用:
    awk "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 — 仅查看价格通知(不执行交易)