refactor: rewrite Coin Hunter as short-term trading framework with auto-trading architecture
This commit is contained in:
380
SKILL.md
380
SKILL.md
@@ -1,296 +1,164 @@
|
||||
---
|
||||
name: Coin Hunter
|
||||
description: Hunt, triage, and compare speculative crypto coins — especially meme coins, 妖币-style runners, fake-hype pumps, and possible rug/scam setups. Use when a user wants to actively search for coins with breakout potential, rank a shortlist, ask whether a coin still has "妖性", or check whether a token looks late, fragile, manipulated, or likely to be a scam.
|
||||
description: Hybrid short-term crypto trading system — combining mainstream coin scalping with meme-coin opportunistic rotation, backed by hourly review and continuous strategy iteration.
|
||||
---
|
||||
|
||||
# Coin Hunter
|
||||
|
||||
## Overview
|
||||
|
||||
Use this skill to help a user search for and judge **high-volatility crypto setups** without pretending certainty.
|
||||
Coin Hunter is a **short-term trading framework**, not just a meme-coin scanner.
|
||||
|
||||
Default buckets:
|
||||
- **candidate runner** — has ingredients for further speculative expansion
|
||||
- **watch-only / incomplete** — interesting, but not clean enough yet
|
||||
- **late / overheated** — may still move, but entry quality is already poor
|
||||
- **avoid / scam-risk** — liquidity, distribution, credibility, or structure is too weak
|
||||
It operates on two tracks:
|
||||
1. **Mainstream Short-Term (70%)** — Trade liquid, high-volume coins (BTC, ETH, SOL, DOGE, PEPE, etc.) based on technical momentum, support/resistance, and market structure.
|
||||
2. **Meme / 妖币 Rotation (30%)** — Opportunistically rotate into breakout meme coins when narrative heat, volume, and timing align.
|
||||
|
||||
Frame the work as **speculative pattern recognition**, not investment advice.
|
||||
Core principle:
|
||||
- **Profit maximization through concentration + discipline.**
|
||||
- **妖币可遇不可求** — when a runner appears, capture it. When none exists, do not force trades; instead, scalp mainstream coins or sit in USDT.
|
||||
- Every decision is logged, and every hour is reviewed for quality and parameter tuning.
|
||||
|
||||
## Core rule
|
||||
## Portfolio-first rule
|
||||
|
||||
Judge a coin by **attention + liquidity + distribution + timing** first. Narrative matters, but only when it can attract and hold money.
|
||||
Always check the user's actual portfolio state under `~/.coinhunter/` before giving trade advice or executing orders.
|
||||
|
||||
A technically weak project can still become a runner. A sophisticated-looking project can still be dead money.
|
||||
Files to inspect:
|
||||
- `positions.json`
|
||||
- `accounts.json`
|
||||
- `logs/decisions_YYYYMMDD.jsonl`
|
||||
- `logs/trades_YYYYMMDD.jsonl`
|
||||
- `reviews/review_YYYYMMDD_HHMMSS.json`
|
||||
|
||||
## Supported request types
|
||||
Anchor all advice to the user's real balances, average costs, exchange, and current exposure.
|
||||
|
||||
Use this skill for four common modes:
|
||||
- **single-coin triage** — "look at this coin"
|
||||
- **active discovery** — "find me coins that could become 妖币"
|
||||
- **shortlist ranking** — "which of these 5 is most interesting"
|
||||
- **scam / rug check** — "is this coin just fake hype"
|
||||
## Supported modes
|
||||
|
||||
If the request is broad, ask at most **one compact clarifying question**. Prefer:
|
||||
- chain
|
||||
- theme / narrative
|
||||
- risk level
|
||||
- whether the user accepts microcaps or wants only reasonably tradable names
|
||||
1. **Single-coin triage** — analyze a specific holding (mainstream or meme).
|
||||
2. **Active discovery** — scan for the best short-term opportunity across both mainstream and meme sectors.
|
||||
3. **Execution** — run the auto-trader, evaluate whether to hold, sell, or rebalance.
|
||||
4. **Review** — generate an hourly report on decision quality, PnL, and recommended parameter adjustments.
|
||||
|
||||
If no preference is given, default to: **liquid speculative candidates, not ultra-illiquid microcaps**.
|
||||
## Scientific analysis checklist (mandatory before every trade decision)
|
||||
|
||||
Before executing or recommending any action, answer:
|
||||
1. **Trend posture** — Is price above/below short-term MAs (1h/4h)?
|
||||
2. **Volume-price fit** — Is volume expanding with the move or diverging?
|
||||
3. **Key levels** — Where is the next support/resistance? How much room to run?
|
||||
4. **Market context** — Is BTC/ETH supportive or contradictory?
|
||||
5. **Opportunity cost** — Is holding current coin better than switching to new coin or sitting in USDT?
|
||||
6. **Time window** — Is this a good entry/exit time (liquidity, session, news flow)?
|
||||
|
||||
Read `references/short-term-trading-framework.md` before every active decision pass.
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Identify the mode
|
||||
### Discovery & Scanning
|
||||
1. **Mainstream scan** — Use `market_probe.py bybit-ticker` or ccxt for liquid coins.
|
||||
- Look for: breakouts, volume spikes, S/R flips, trend alignment.
|
||||
2. **Meme scan** — Use `web_search` + `dex-search` / `gecko-search` for narrative heat.
|
||||
- Look for: accelerating attention, DEX flow, CEX listing rumors, social spread.
|
||||
3. **Cross-compare** — Score the top 3-5 candidates against current holdings.
|
||||
|
||||
Decide whether the user wants:
|
||||
- discovery
|
||||
- triage
|
||||
- comparison
|
||||
- scam-check
|
||||
### Execution
|
||||
1. Read balances and positions.
|
||||
2. Pull market data for holdings and candidates.
|
||||
3. Run the 6-question scientific checklist.
|
||||
4. Decide: **HOLD** / **SELL_ALL** / **REBALANCE** / **BUY**.
|
||||
5. Execute via `smart_executor.py`.
|
||||
6. Log the full decision context with `logger.py`.
|
||||
|
||||
Then bias the workflow accordingly.
|
||||
### Review (every hour)
|
||||
1. Run `review_engine.py` to analyze all decisions from the past hour.
|
||||
2. Compare decision prices to current prices.
|
||||
3. Flag patterns: missed runs, bad entries, over-trading, hesitation.
|
||||
4. Output recommendations for parameter or blacklist adjustments.
|
||||
5. Save the review report to `~/.coinhunter/reviews/`.
|
||||
|
||||
### 2. Choose the data path
|
||||
## Auto-trading architecture
|
||||
|
||||
Use **structured market data first** when available. Use web search to discover names and collect context, not as the only source of truth.
|
||||
| Component | Path | Purpose |
|
||||
|-----------|------|---------|
|
||||
| `smart_executor.py` | `~/.coinhunter/smart_executor.py` | Order execution layer (market buy/sell/rebalance) |
|
||||
| `logger.py` | `~/.coinhunter/logger.py` | Records decisions, trades, and market snapshots |
|
||||
| `review_engine.py` | `~/.coinhunter/review_engine.py` | Hourly quality review and optimization suggestions |
|
||||
| `market_probe.py` | `~/.hermes/skills/coinhunter/scripts/market_probe.py` | Market data fetcher |
|
||||
|
||||
Preferred source order:
|
||||
- **Bybit** for real-time-ish price, 24h turnover, and tradability on a major venue
|
||||
- **DexScreener** for meme-coin pair discovery, DEX liquidity, and small-cap flow
|
||||
- **Birdeye** for Solana token activity and confirmation
|
||||
- **CoinGecko** for market-cap, rank, and metadata cross-check
|
||||
- **web_search** for discovery, narratives, and scam-discussion context
|
||||
### Execution schedule
|
||||
- **Trade bot** — runs every 15-30 minutes via `cronjob`.
|
||||
- **Review bot** — runs every 1-12 hours via `cronjob`, depending on how much manual oversight is needed.
|
||||
|
||||
Private user state must live outside the skill directory under `~/.coinhunter/`, not inside `skills/coinhunter/`.
|
||||
Read `references/provider-playbook.md` when choosing which source to trust first.
|
||||
Read `references/user-data-layout.md` when adding or updating personal accounts, positions, watchlists, or notes.
|
||||
Use `scripts/market_probe.py` for deterministic provider lookups.
|
||||
Use `scripts/init_user_state.py` to initialize the private user-data directory.
|
||||
### Low-cost cron architecture
|
||||
When model cost or quota is tight, do not let every cron run perform full analysis from scratch.
|
||||
|
||||
### 3. Discovery mode: build a candidate list
|
||||
Recommended pattern:
|
||||
1. Attach a lightweight Python `script` to the cron job (under `~/.hermes/scripts/`) that fetches balances/tickers, computes hashes, and emits compact JSON context.
|
||||
2. Cache the last observed positions, top candidates, market regime, and `last_deep_analysis_at` under `~/.coinhunter/state/`.
|
||||
3. Trigger full analysis only when one of these changes materially. Make the thresholds adaptive instead of fixed:
|
||||
- position structure changes (hard trigger)
|
||||
- per-position price/PnL moves beyond thresholds that widen for micro-capital / dust accounts and narrow during higher-volatility sessions
|
||||
- top candidate leadership changes materially, but discount this signal when free USDT is below actionable exchange minimums
|
||||
- BTC/ETH regime changes (hard trigger)
|
||||
- a max staleness timer forces refresh, with longer refresh windows for micro accounts to avoid pointless re-analysis
|
||||
4. In the cron prompt, if the injected context says `should_analyze=false`, respond with exactly `[SILENT]` and do not call tools.
|
||||
5. After a triggered deep-analysis pass completes, acknowledge it from the agent (for example by running the precheck script with an `--ack` flag) so the trigger is cleared.
|
||||
7. For even lower spend, move the high-frequency cadence outside Hermes cron entirely:
|
||||
- install a system `crontab` entry that runs a local gate script every 5-10 minutes
|
||||
- let that gate script run the lightweight precheck
|
||||
- only when `should_analyze=true` and no run is already queued, trigger the Hermes cron job via `hermes cron run <job_id>`
|
||||
- store a `run_requested_at` marker in `~/.coinhunter/state/precheck_state.json` and clear it when the analysis acknowledges completion
|
||||
|
||||
When the user wants active search rather than analysis of a known ticker, use public web sources to build a shortlist.
|
||||
This pattern preserves Telegram auto-delivery from Hermes cron while reducing model wakeups to trigger-only events.
|
||||
|
||||
Look for evidence of:
|
||||
- rising attention
|
||||
- listing or venue expansion
|
||||
- narrative/theme alignment
|
||||
- market-cap and liquidity context
|
||||
- breakout discussion or unusual participation
|
||||
### Practical production notes for external gate mode
|
||||
- Put the external gate itself on system `crontab` (for example every 5 minutes) rather than on Hermes cron. That keeps the high-frequency loop completely local and model-free.
|
||||
- Keep the Hermes trading cron job on a low-frequency fallback schedule (for example once daily at 05:00 local time) so the main execution path remains trigger-driven.
|
||||
- Add a file lock around the external gate script so overlapping system-cron invocations cannot double-trigger.
|
||||
- Rotate `~/.coinhunter/logs/external_gate.log` with `logrotate` (daily, keep ~14 compressed copies, `copytruncate`) and schedule the rotation a few minutes after the fallback Hermes cron run so they do not overlap.
|
||||
|
||||
Useful search patterns include:
|
||||
- `<theme> meme coin trending`
|
||||
- `<chain> meme coin watchlist`
|
||||
- `new meme coin listed`
|
||||
- `<coin> market cap liquidity`
|
||||
- `<coin> holders tokenomics`
|
||||
- `<coin> rug risk`
|
||||
### Production hardening (mandatory)
|
||||
The live trading stack must include these safeguards:
|
||||
1. **Idempotency** — every decision carries a `decision_id`. The executor checks `~/.coinhunter/executions.json` before submitting orders to prevent duplicate trades.
|
||||
2. **Exchange reconciliation** — before every run, pull real Binance balances and recent trades to sync `positions.json`. Do not trust local state alone.
|
||||
3. **File locking + atomic writes** — `positions.json` and `executions.json` are updated under a file lock and written to a temp file before atomic rename.
|
||||
4. **Order precision validation** — read Binance `lotSize`, `stepSize`, and `minNotional` filters via ccxt before any order. Round quantities correctly and reject orders below minimums.
|
||||
5. **Fee buffer** — keep ~2%-5% USDT unallocated so that slippage and fees do not cause "insufficient balance" rejections.
|
||||
6. **Structured logging** — every decision, trade, error, and balance snapshot is written as JSONL under `~/.coinhunter/logs/` with `schema_version` and `decision_id`.
|
||||
7. **Error logging** — failed API calls, rejected orders, and reconciliation mismatches are captured in `logs/errors_YYYYMMDD.jsonl` and fed into the hourly review.
|
||||
|
||||
Do not trust a single source or a single viral thread. Build the list first, then vet the names.
|
||||
## Safety rules
|
||||
- No leverage/futures when capital < $200.
|
||||
- When capital < $50, concentrate into **1 position only**.
|
||||
- Always leave 2%-5% USDT buffer for fees and slippage.
|
||||
- Blacklist updates should be driven by review findings.
|
||||
|
||||
Read `references/search-workflow.md` for the detailed discovery flow.
|
||||
## Position sizing
|
||||
|
||||
### 4. Triage mode: score the coin on six dimensions
|
||||
|
||||
Assess each coin qualitatively across these dimensions.
|
||||
|
||||
#### A. Narrative fit
|
||||
Ask:
|
||||
- Is the story attached to a live theme?
|
||||
- Is the idea easy to repeat in one sentence?
|
||||
- Does the symbol / meme / framing have social spread potential?
|
||||
|
||||
Strong examples:
|
||||
- obvious meme identity
|
||||
- attached to a live chain or hot sector
|
||||
- easy cultural hook
|
||||
|
||||
Weak examples:
|
||||
- vague utility story
|
||||
- no memorable angle
|
||||
- cold or stale narrative
|
||||
|
||||
#### B. Attention acceleration
|
||||
Ask:
|
||||
- Is visibility rising now?
|
||||
- Is the coin spreading beyond its original niche?
|
||||
- Are larger accounts, aggregators, or trading communities starting to notice it?
|
||||
|
||||
Treat **acceleration** as more important than absolute popularity.
|
||||
|
||||
#### C. Liquidity quality
|
||||
Ask:
|
||||
- Can a normal user realistically enter and exit?
|
||||
- Is volume believable relative to market cap and attention?
|
||||
- Are spreads or venue quality obviously problematic?
|
||||
|
||||
If the user can probably buy but may not be able to exit cleanly, score this harshly.
|
||||
|
||||
#### D. Distribution / holder risk
|
||||
Ask:
|
||||
- Is ownership too concentrated?
|
||||
- Are deployer or team wallets still dangerous?
|
||||
- Is there an obvious unlock or dump overhang?
|
||||
|
||||
Ugly distribution does not automatically kill a trade, but it makes the setup fragile.
|
||||
|
||||
#### E. Timing / chart state
|
||||
Ask:
|
||||
- Is it emerging from a base or already vertical?
|
||||
- Has participation expanded recently?
|
||||
- Do pullbacks hold, or do they collapse?
|
||||
|
||||
Prefer:
|
||||
- fresh breakout from longer consolidation
|
||||
- early or mid-stage expansion
|
||||
- resilient retraces
|
||||
|
||||
Be cautious when:
|
||||
- it already went parabolic
|
||||
- volume fades after the first mania burst
|
||||
- price action is mostly wick-and-dump behavior
|
||||
|
||||
#### F. Rug / scam risk
|
||||
Check for:
|
||||
- fake partnerships or fake listing claims
|
||||
- unverifiable team paired with aggressive promotion
|
||||
- suspicious contract / public warning signals
|
||||
- impossible tokenomics promises
|
||||
- unverified liquidity-lock claims
|
||||
- nothing but shill posts and no independent discussion
|
||||
|
||||
One severe scam signal can outweigh several bullish ones.
|
||||
Read `references/scam-signals.md` when the user specifically asks about rugs, scams, fake hype, manipulation, or exit-liquidity bait.
|
||||
|
||||
### 5. Classify the result
|
||||
|
||||
Use these buckets:
|
||||
|
||||
#### Candidate runner
|
||||
Use when most are true:
|
||||
- narrative is live
|
||||
- attention is accelerating
|
||||
- liquidity is usable
|
||||
- timing is not obviously exhausted
|
||||
- no fatal scam / exit-risk signal is present
|
||||
|
||||
#### Watch-only / incomplete
|
||||
Use when:
|
||||
- something is interesting, but evidence is incomplete
|
||||
- narrative is decent but timing is unclear
|
||||
- liquidity or distribution is acceptable but not clean
|
||||
- it deserves monitoring more than action
|
||||
|
||||
#### Late / overheated
|
||||
Use when:
|
||||
- the move is already widely noticed
|
||||
- chart is extended or near blow-off behavior
|
||||
- upside may remain, but entry quality is poor
|
||||
- new buyers are at risk of becoming exit liquidity
|
||||
|
||||
#### Avoid / scam-risk
|
||||
Use when:
|
||||
- liquidity quality is bad
|
||||
- exit risk is high
|
||||
- holder concentration is dangerous
|
||||
- legitimacy claims are weak or fake
|
||||
- the setup feels more fabricated than organic
|
||||
|
||||
## Provider execution patterns
|
||||
|
||||
### Known tradable coin
|
||||
If the user gives a Bybit-listed ticker or asks for current price/tradability:
|
||||
1. run `python3 scripts/market_probe.py bybit-ticker <SYMBOL>`
|
||||
2. optionally run `python3 scripts/market_probe.py bybit-klines <SYMBOL> --interval 60 --limit 10`
|
||||
3. cross-check with CoinGecko when market-cap context matters
|
||||
|
||||
### Meme / 妖币 discovery
|
||||
If the user wants runners, meme coins, or small-cap candidates:
|
||||
1. use `web_search` to gather names
|
||||
2. run `python3 scripts/market_probe.py dex-search <name>` for the strongest candidates
|
||||
3. if Solana, run Birdeye when API access is configured
|
||||
4. use CoinGecko to verify market-cap and ranking
|
||||
5. only use Bybit if the coin is also on a major CEX
|
||||
|
||||
### Birdeye requirement
|
||||
`market_probe.py birdeye-token <address>` requires `BIRDEYE_API_KEY` in the environment. If it is not configured, say so briefly and continue with DexScreener + CoinGecko + web search.
|
||||
|
||||
### Private portfolio state
|
||||
If the user wants account, position, watchlist, or thesis tracking for coinhunter:
|
||||
1. initialize `~/.coinhunter/` with `python3 scripts/init_user_state.py`
|
||||
2. store private data only there
|
||||
3. never place personal holdings inside the skill folder
|
||||
4. treat the skill folder as logic only, and the user-data directory as state only
|
||||
| Total Capital | Strategy |
|
||||
|---------------|----------|
|
||||
| < $50 | Single-coin concentration (mainstream or meme) |
|
||||
| $50 – $200 | 60% mainstream + 40% meme, max 2 positions |
|
||||
| > $200 | Up to 3 positions with stricter risk per position |
|
||||
|
||||
## Output style
|
||||
|
||||
Default to **compact, decision-first** answers.
|
||||
### For live decisions
|
||||
Concise Telegram-style report:
|
||||
- Current holdings + live PnL
|
||||
- Top 1-2 opportunities found
|
||||
- Decision and exact reasoning
|
||||
- Action confirmation (or [DRY RUN] note)
|
||||
|
||||
For a single coin, include:
|
||||
- **Verdict**
|
||||
- **Radar score** — use the 0-12 checklist when evidence is sufficient
|
||||
- **Why it could run** — 2-4 bullets
|
||||
- **Why it could fail** — 2-4 bullets
|
||||
- **What confirms strength**
|
||||
- **What kills the thesis**
|
||||
- **Risk line** — clearly state this is speculative, not investment advice
|
||||
|
||||
For multiple coins:
|
||||
1. rank the shortlist
|
||||
2. mark each as candidate runner / watch-only / late / avoid
|
||||
3. state the main attraction and main flaw for each
|
||||
|
||||
Prefer bullets, short sections, and hard judgments over long essays.
|
||||
Use `references/output-templates.md` when you want a reusable answer skeleton.
|
||||
|
||||
## Practical heuristics
|
||||
|
||||
### Often bullish for speculative expansion
|
||||
- the meme or story is instantly repeatable
|
||||
- attention is accelerating, not just present
|
||||
- volume expands with the move
|
||||
- pullbacks are bought
|
||||
- exchange accessibility improves
|
||||
- more mainstream crypto accounts begin to mention it
|
||||
|
||||
### Often a sign it is late
|
||||
- everyone is already talking about it
|
||||
- the chart has been vertical for days
|
||||
- promotion is everywhere after the main move already happened
|
||||
- price keeps spiking while structure gets messier
|
||||
|
||||
### Often a sign to avoid
|
||||
- no trustworthy liquidity information
|
||||
- suspicious ownership concentration
|
||||
- clearly manufactured chart behavior
|
||||
- incoherent or constantly shifting explanation
|
||||
- obviously botted or repetitive social activity
|
||||
|
||||
## What not to do
|
||||
|
||||
- Do not describe a coin as safe.
|
||||
- Do not confuse a polished whitepaper with breakout potential.
|
||||
- Do not imply expected returns.
|
||||
- Do not recommend leverage.
|
||||
- Do not ignore slippage and exit risk.
|
||||
- Do not push microcaps on beginners unless the user explicitly asks for extreme risk.
|
||||
|
||||
## Optional deeper pass
|
||||
|
||||
If the user wants more depth, expand in this order:
|
||||
1. narrative and timing
|
||||
2. liquidity and market structure
|
||||
3. holder / tokenomics risk
|
||||
4. why it could become a runner
|
||||
5. why it probably will not
|
||||
6. watch triggers
|
||||
### For hourly reviews
|
||||
Use `references/review-template.md` structure:
|
||||
- Decision quality breakdown
|
||||
- Market context
|
||||
- Strategy adjustments recommended
|
||||
- Action items for next hour
|
||||
|
||||
## References
|
||||
|
||||
Read `references/provider-playbook.md` for source selection and provider roles.
|
||||
Read `references/user-data-layout.md` for private state layout under `~/.coinhunter/`.
|
||||
Read `references/radar-checklist.md` for a quick scoring framework.
|
||||
Read `references/search-workflow.md` for active discovery.
|
||||
Read `references/output-templates.md` for compact response structure.
|
||||
Read `references/scam-signals.md` for sharper scam / fake-hype judgment.
|
||||
Read `references/provider-playbook.md` for data source selection.
|
||||
Read `references/user-data-layout.md` for private state management.
|
||||
Read `references/short-term-trading-framework.md` for the hybrid trading framework.
|
||||
Read `references/review-template.md` for hourly report formatting.
|
||||
Read `references/scam-signals.md` when evaluating meme coins.
|
||||
|
||||
197
references/auto-trading-guide.md
Normal file
197
references/auto-trading-guide.md
Normal file
@@ -0,0 +1,197 @@
|
||||
# Automated Trading Guide for Coin Hunter
|
||||
|
||||
Complete guide for building and running a hands-off meme-coin trading bot using the Binance Spot API.
|
||||
|
||||
## Scope
|
||||
|
||||
This guide covers:
|
||||
- Creating a safe Binance API key
|
||||
- Installing dependencies (ccxt, pandas, numpy)
|
||||
- Setting up `auto_trader.py`
|
||||
- Testing in `DRY_RUN` mode
|
||||
- Scheduling execution with `cronjob`
|
||||
- Critical safety rules and troubleshooting
|
||||
|
||||
## What the bot does
|
||||
|
||||
1. **Monitors existing positions** for stop-loss (-7%) and take-profit (+15% / +30%) levels
|
||||
2. **Scans the market** for new meme-coin candidates (price < $1, 24h volume > $1M, 24h change > 5%)
|
||||
3. **Dynamically sizes orders** based on the user's total USDT balance and a configurable allocation percentage
|
||||
4. **Runs on a schedule** (default every 15 minutes) and reports actions back via Telegram
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
~/.coinhunter/
|
||||
├── auto_trader.py # Main trading logic
|
||||
├── run_trader.sh # Shell wrapper (venv + env vars + logging)
|
||||
├── check_api.py # Quick API connectivity validator
|
||||
├── logs/trader.log # Execution logs
|
||||
└── positions.json # Portfolio state (shared with coinhunter)
|
||||
```
|
||||
|
||||
## Step 1: Binance API Key setup
|
||||
|
||||
1. Log in to Binance → **API Management**
|
||||
2. Create a new API Key
|
||||
3. Enable permissions:
|
||||
- ✅ **Enable Reading**
|
||||
- ✅ **Enable Spot & Margin Trading**
|
||||
- ❌ **Disable Withdrawal** (security red line)
|
||||
4. Add an **IP whitelist** (strongly recommended):
|
||||
- Use the public IP of the machine that will run the bot
|
||||
- This prevents key reuse if the credential is ever leaked
|
||||
|
||||
**Security reminder:** never paste API keys into chat messages. Write them directly into `~/.hermes/.env`.
|
||||
|
||||
## Step 2: Store credentials
|
||||
|
||||
Append to `~/.hermes/.env`:
|
||||
|
||||
```env
|
||||
BINANCE_API_KEY=your_api_key_here
|
||||
BINANCE_API_SECRET=your_api_secret_here
|
||||
```
|
||||
|
||||
## Step 3: Install dependencies
|
||||
|
||||
The bot uses `ccxt` for exchange connectivity and `pandas`/`numpy` for data handling.
|
||||
|
||||
```bash
|
||||
uv pip install ccxt pandas numpy
|
||||
```
|
||||
|
||||
Or if using a venv:
|
||||
|
||||
```bash
|
||||
source venv/bin/activate
|
||||
pip install ccxt pandas numpy
|
||||
```
|
||||
|
||||
## Step 4: Deploy the bot
|
||||
|
||||
Use `scripts/auto_trader.py` from the coinhunter skill as the template. Copy it into the user's `~/.coinhunter/` directory and customize:
|
||||
|
||||
- `MAX_POSITIONS` — max concurrent meme-coin positions (default 2)
|
||||
- `CAPITAL_ALLOCATION_PCT` — fraction of total USDT to use (default 0.95; leave ~5% buffer for fees/slippage)
|
||||
- `MIN_POSITION_USDT` — minimum single order size (default 50)
|
||||
- `STOP_LOSS_PCT` / `TAKE_PROFIT_1_PCT` / `TAKE_PROFIT_2_PCT` — risk levels
|
||||
|
||||
Create `run_trader.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
python3 check_api.py
|
||||
source /path/to/venv/bin/activate
|
||||
export DRY_RUN=${DRY_RUN:-true}
|
||||
python3 auto_trader.py >> logs/trader.log 2>&1
|
||||
```
|
||||
|
||||
Make executable:
|
||||
|
||||
```bash
|
||||
chmod +x run_trader.sh check_api.py
|
||||
mkdir -p logs
|
||||
```
|
||||
|
||||
## Step 5: Validate API connectivity
|
||||
|
||||
```bash
|
||||
python3 check_api.py
|
||||
```
|
||||
|
||||
Expected output: `✅ API 配置正常`
|
||||
|
||||
If this fails, the bot will exit immediately on each run.
|
||||
|
||||
## Step 6: Run a DRY_RUN test
|
||||
|
||||
```bash
|
||||
DRY_RUN=true python3 auto_trader.py
|
||||
```
|
||||
|
||||
Expected behavior:
|
||||
- Reads current positions from `positions.json`
|
||||
- Fetches live Binance prices
|
||||
- Prints PnL for each position
|
||||
- Prints `[DRY RUN]` instead of real trades
|
||||
- Does **not** move money
|
||||
|
||||
Only proceed to live trading after at least one dry-run cycle completes without errors.
|
||||
|
||||
## Step 7: Schedule with cronjob
|
||||
|
||||
Use the `cronjob` tool to run the bot every 15 minutes:
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "create",
|
||||
"name": "Coin Hunter Auto Trader",
|
||||
"schedule": "*/15 * * * *",
|
||||
"deliver": "telegram",
|
||||
"prompt": "Run the Coin Hunter automatic meme-coin trading bot.\n1. cd /home/<user>/.coinhunter\n2. ./run_trader.sh\n3. Summarize actions and report back."
|
||||
}
|
||||
```
|
||||
|
||||
## Step 8: Switch to live trading
|
||||
|
||||
Once DRY_RUN validation succeeds and the user confirms:
|
||||
|
||||
1. Edit `run_trader.sh`
|
||||
2. Change `DRY_RUN=${DRY_RUN:-true}` to `DRY_RUN=${DRY_RUN:-false}`
|
||||
3. The next cron run will execute real orders
|
||||
|
||||
**You must always obtain explicit user confirmation before enabling live trading.**
|
||||
|
||||
## Key safety rules
|
||||
|
||||
1. **Never enable Withdrawal permission** on the API key.
|
||||
2. **Always bind an IP whitelist** if possible.
|
||||
3. **Never accept API keys in plaintext chat.** Ask the user to write them into `~/.hermes/.env`.
|
||||
4. **Do not set allocation to exactly 100%.** Leave at least 3–5% buffer for fees and slippage.
|
||||
5. **Start with DRY_RUN.** Run at least one full cycle before going live.
|
||||
6. **Check the account balance first.** If USDT is 0 (or held in Earn/Margin/Futures), the bot cannot trade.
|
||||
7. **Educate the user about risks.** Automated bots can and will lose money during flash crashes, API errors, or black-swan events.
|
||||
|
||||
## Common pitfalls
|
||||
|
||||
### Ticker symbol mismatch
|
||||
|
||||
ccxt returns tickers with a slash (e.g., `PENGU/USDT`), but `positions.json` may store symbols without a slash (`PENGUUSDT`). If the bot looks up `tickers.get("PENGUUSDT")`, it will get `None` and silently skip stop-loss/take-profit checks.
|
||||
|
||||
**Fix:** normalize symbols before lookup:
|
||||
|
||||
```python
|
||||
sym_ccxt = sym.replace("USDT", "/USDT") if "/" not in sym else sym
|
||||
ticker = tickers.get(sym_ccxt)
|
||||
```
|
||||
|
||||
### .env file is protected
|
||||
|
||||
The `patch` tool may reject edits to `~/.hermes/.env`. Use terminal redirection instead:
|
||||
|
||||
```bash
|
||||
cat >> ~/.hermes/.env << 'EOF'
|
||||
BINANCE_API_KEY=xxx
|
||||
BINANCE_API_SECRET=yyy
|
||||
EOF
|
||||
```
|
||||
|
||||
### Zero balance surprises
|
||||
|
||||
The bot reads **Spot free balance**. If the user holds USDT in:
|
||||
- Flexible Savings / Earn
|
||||
- Margin account
|
||||
- Futures wallet
|
||||
- Another sub-account
|
||||
|
||||
…it will see $0 and fail to open new positions. Ask the user to transfer funds to Spot before going live.
|
||||
|
||||
## Customization ideas
|
||||
|
||||
- **Chain bias:** restrict candidate scanning to Solana-only or Base-only by filtering `cand["base"]` or integrating DexScreener chain filters.
|
||||
- **Social signal integration:** add a Twitter/X sentiment check before opening a position.
|
||||
- **Tiered stops:** replace fixed -7% with trailing stops using recent ATR or swing lows.
|
||||
- **Blacklist expansion:** add recently rugged tickers to `BLACKLIST` based on on-chain data.
|
||||
40
references/review-template.md
Normal file
40
references/review-template.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Review Report Template
|
||||
|
||||
## Header
|
||||
- Review Period: [Start] — [End]
|
||||
- Total Decisions: N
|
||||
- Total Trades Executed: N
|
||||
- Portfolio Value Change: +X% / -X%
|
||||
|
||||
## Decision Quality Breakdown
|
||||
|
||||
### 1. Hold Decisions
|
||||
- Count: N
|
||||
- Outcome: [mostly correct / neutral / mostly wrong]
|
||||
- Key Insight: …
|
||||
|
||||
### 2. Sell Decisions
|
||||
- Count: N
|
||||
- Good exits (avoided further drop): N
|
||||
- Missed runs (sold too early): N
|
||||
- Avg opportunity cost of early exits: X%
|
||||
|
||||
### 3. Buy / Rebalance Decisions
|
||||
- Count: N
|
||||
- Profitable entries: N
|
||||
- Losing entries: N
|
||||
- Avg estimated PnL: X%
|
||||
|
||||
## Market Context During Period
|
||||
- BTC trend: [up / down / sideways]
|
||||
- Dominant narrative: …
|
||||
- Liquidity condition: [high / normal / low]
|
||||
|
||||
## Strategy Adjustments Recommended
|
||||
1. …
|
||||
2. …
|
||||
3. …
|
||||
|
||||
## Action Items for Next Hour
|
||||
- [ ] …
|
||||
- [ ] …
|
||||
78
references/short-term-trading-framework.md
Normal file
78
references/short-term-trading-framework.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Short-Term Trading Framework
|
||||
|
||||
## Philosophy
|
||||
|
||||
不要只狩猎妖币。短线复利的核心是**在高确率/高赔付比的机会上重仓,在不确定时观望**。
|
||||
|
||||
妖币是可遇不可求的赚钱机会,遇到了不要错过,没遇到也不要强求。当市场缺乏明确的超短线热点时,主流币的短线波动率交易往往更稳定。
|
||||
|
||||
---
|
||||
|
||||
## Strategy Mix
|
||||
|
||||
### 1. Mainstream Short-Term (70% of focus)
|
||||
**Target coins:** BTC, ETH, SOL, BNB, DOGE, PEPE, WIF, BONK 等 Binance 高流动性币种
|
||||
|
||||
**Entry triggers:**
|
||||
- 突破关键阻力/支撑位,并且放量
|
||||
- 1h / 4h 级别出现明确的趋势转折信号
|
||||
- 超卖/超买指标出现极端值且开始回归
|
||||
- 量价齐升(Volume 放大 + 价格突破)
|
||||
|
||||
**Exit triggers:**
|
||||
- 达到预设盈亏目标(主流币 +8% 至 +15%)
|
||||
- 趋势转弱信号(量缩价跌、失守关键支撑)
|
||||
- 出现更好的机会成本(换仓)
|
||||
|
||||
**Risk management:**
|
||||
- 单次下注不超过总资产的 50%
|
||||
- 主流币硬止损放宽至 -5% 至 -8%
|
||||
- 使用支撑阻力作为活止损,不用固定百分比
|
||||
|
||||
### 2. Meme / 妖币 Rotation (30% of focus)
|
||||
**Target coins:** 新兴 meme、热点小币
|
||||
|
||||
**Entry triggers:**
|
||||
- 社交媒体关注度快速上升
|
||||
- 24h 成交量 > $1M
|
||||
- 币安可交易(确保能进能出)
|
||||
- 故事/narrative 简单易传播
|
||||
|
||||
**Exit triggers:**
|
||||
- 涨幅过快(+50% in 24h)且量缩
|
||||
- 舆论出现转凇信号
|
||||
- 新币出现更强势代替
|
||||
|
||||
---
|
||||
|
||||
## Scientific Analysis Checklist
|
||||
|
||||
每次决策前,必须回答以下问题:
|
||||
|
||||
1. **趋势态势**:价格在短期均线(1h/4h MA)的上方还是下方?
|
||||
2. **量能配合**:最近几个 K 线的成交量是否配合价格走势?
|
||||
3. **关键位置**:下一个支撑和阻力在哪里?空间有多大?
|
||||
4. **市场情绪**:大盘(BTC/ETH)是否配合?还是独立行情?
|
||||
5. **机会成本**:持有现币 vs 换到新币 vs 持有现金,三者中谁的风险收益比最优?
|
||||
6. **时间窗口**:现在是否是合适的入市/出市时间点?(注意交易所交易时间段的流动性变化)
|
||||
|
||||
---
|
||||
|
||||
## Position Sizing
|
||||
|
||||
根据总资产动态调整:
|
||||
- 当总资产 < $50:**单币重仓**,放弃多元化
|
||||
- 当总资产 $50-$200:主流币 60% + 妖币 40%
|
||||
- 当总资产 > $200:可考虑 3 个币的轮动
|
||||
|
||||
不论资金大小,都要留出至少 2%-5% 的 USDT 缓冲以应对手续费和滑点。
|
||||
|
||||
---
|
||||
|
||||
## Continuous Improvement
|
||||
|
||||
每小时复盘一次,重点关注:
|
||||
- 是否有连续出现同类型的决策失误
|
||||
- 是否过于频繁交易(摩擦成本过高)
|
||||
- 是否在明显的指标背离时仍然入市
|
||||
- 新闻/市场视角是否需要更新到黑名单或基准条件中
|
||||
277
scripts/auto_trader.py
Normal file
277
scripts/auto_trader.py
Normal file
@@ -0,0 +1,277 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Coin Hunter Auto Trader Template
|
||||
全自动妖币猎人 + 币安执行器
|
||||
|
||||
运行前请在 ~/.hermes/.env 配置:
|
||||
BINANCE_API_KEY=你的API_KEY
|
||||
BINANCE_API_SECRET=你的API_SECRET
|
||||
|
||||
首次运行必须先用 DRY_RUN=true 测试逻辑!
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
import ccxt
|
||||
|
||||
# ============== 配置 ==============
|
||||
COINS_DIR = Path.home() / ".coinhunter"
|
||||
POSITIONS_FILE = COINS_DIR / "positions.json"
|
||||
ENV_FILE = Path.home() / ".hermes" / ".env"
|
||||
|
||||
# 风控参数
|
||||
DRY_RUN = os.getenv("DRY_RUN", "true").lower() == "true" # 默认测试模式
|
||||
MAX_POSITIONS = 2 # 最大同时持仓数
|
||||
|
||||
# 资金配置(根据总资产动态计算)
|
||||
CAPITAL_ALLOCATION_PCT = 0.95 # 用总资产95%玩这个策略(留95%缓冲给手续费和滑点)
|
||||
MIN_POSITION_USDT = 50 # 单次最小下单金额(避免过小)
|
||||
|
||||
MIN_VOLUME_24H = 1_000_000 # 最小24h成交额 ($)
|
||||
MIN_PRICE_CHANGE_24H = 0.05 # 最小涨幅 5%
|
||||
MAX_PRICE = 1.0 # 只玩低价币(meme特征)
|
||||
STOP_LOSS_PCT = -0.07 # 止损 -7%
|
||||
TAKE_PROFIT_1_PCT = 0.15 # 止盈1 +15%
|
||||
TAKE_PROFIT_2_PCT = 0.30 # 止盈2 +30%
|
||||
BLACKLIST = {"USDC", "BUSD", "TUSD", "FDUSD", "USTC", "PAXG", "XRP", "ETH", "BTC"}
|
||||
|
||||
# ============== 工具函数 ==============
|
||||
def log(msg: str):
|
||||
print(f"[{datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S')} UTC] {msg}")
|
||||
|
||||
|
||||
def load_positions() -> list:
|
||||
if POSITIONS_FILE.exists():
|
||||
return json.loads(POSITIONS_FILE.read_text(encoding="utf-8")).get("positions", [])
|
||||
return []
|
||||
|
||||
|
||||
def save_positions(positions: list):
|
||||
COINS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
POSITIONS_FILE.write_text(json.dumps({"positions": positions}, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||
|
||||
|
||||
def load_env():
|
||||
if ENV_FILE.exists():
|
||||
for line in ENV_FILE.read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#") and "=" in line:
|
||||
key, val = line.split("=", 1)
|
||||
os.environ.setdefault(key.strip(), val.strip())
|
||||
|
||||
|
||||
def calculate_position_size(total_usdt: float, available_usdt: float, open_slots: int) -> float:
|
||||
"""
|
||||
根据总资产动态计算每次下单金额。
|
||||
逻辑:先确定策略总上限,再按剩余开仓位均分。
|
||||
"""
|
||||
strategy_cap = total_usdt * CAPITAL_ALLOCATION_PCT
|
||||
used_in_strategy = max(0, strategy_cap - available_usdt)
|
||||
remaining_strategy_cap = max(0, strategy_cap - used_in_strategy)
|
||||
|
||||
if open_slots <= 0 or remaining_strategy_cap < MIN_POSITION_USDT:
|
||||
return 0
|
||||
|
||||
size = remaining_strategy_cap / open_slots
|
||||
size = min(size, available_usdt)
|
||||
size = max(0, round(size, 2))
|
||||
return size if size >= MIN_POSITION_USDT else 0
|
||||
|
||||
|
||||
# ============== 币安客户端 ==============
|
||||
class BinanceTrader:
|
||||
def __init__(self):
|
||||
api_key = os.getenv("BINANCE_API_KEY")
|
||||
secret = os.getenv("BINANCE_API_SECRET")
|
||||
if not api_key or not secret:
|
||||
raise RuntimeError("缺少 BINANCE_API_KEY 或 BINANCE_API_SECRET,请配置 ~/.hermes/.env")
|
||||
self.exchange = ccxt.binance({
|
||||
"apiKey": api_key,
|
||||
"secret": secret,
|
||||
"options": {"defaultType": "spot"},
|
||||
"enableRateLimit": True,
|
||||
})
|
||||
self.exchange.load_markets()
|
||||
|
||||
def get_balance(self, asset: str = "USDT") -> float:
|
||||
bal = self.exchange.fetch_balance()["free"].get(asset, 0)
|
||||
return float(bal)
|
||||
|
||||
def fetch_tickers(self) -> dict:
|
||||
return self.exchange.fetch_tickers()
|
||||
|
||||
def create_market_buy_order(self, symbol: str, amount_usdt: float):
|
||||
if DRY_RUN:
|
||||
log(f"[DRY RUN] 模拟买入 {symbol},金额 ${amount_usdt}")
|
||||
return {"id": "dry-run-buy", "price": None, "amount": amount_usdt}
|
||||
ticker = self.exchange.fetch_ticker(symbol)
|
||||
price = float(ticker["last"])
|
||||
qty = amount_usdt / price
|
||||
order = self.exchange.create_market_buy_order(symbol, qty)
|
||||
log(f"✅ 买入 {symbol} | 数量 {qty:.4f} | 价格 ~${price}")
|
||||
return order
|
||||
|
||||
def create_market_sell_order(self, symbol: str, qty: float):
|
||||
if DRY_RUN:
|
||||
log(f"[DRY RUN] 模拟卖出 {symbol},数量 {qty}")
|
||||
return {"id": "dry-run-sell"}
|
||||
order = self.exchange.create_market_sell_order(symbol, qty)
|
||||
log(f"✅ 卖出 {symbol} | 数量 {qty:.4f}")
|
||||
return order
|
||||
|
||||
|
||||
# ============== 选币引擎 ==============
|
||||
class CoinPicker:
|
||||
def __init__(self, exchange: ccxt.binance):
|
||||
self.exchange = exchange
|
||||
|
||||
def scan(self) -> list:
|
||||
tickers = self.exchange.fetch_tickers()
|
||||
candidates = []
|
||||
for symbol, t in tickers.items():
|
||||
if not symbol.endswith("/USDT"):
|
||||
continue
|
||||
base = symbol.replace("/USDT", "")
|
||||
if base in BLACKLIST:
|
||||
continue
|
||||
|
||||
price = float(t["last"] or 0)
|
||||
change = float(t.get("percentage", 0)) / 100
|
||||
volume = float(t.get("quoteVolume", 0))
|
||||
|
||||
if price <= 0 or price > MAX_PRICE:
|
||||
continue
|
||||
if volume < MIN_VOLUME_24H:
|
||||
continue
|
||||
if change < MIN_PRICE_CHANGE_24H:
|
||||
continue
|
||||
|
||||
score = change * (volume / MIN_VOLUME_24H)
|
||||
candidates.append({
|
||||
"symbol": symbol,
|
||||
"base": base,
|
||||
"price": price,
|
||||
"change_24h": change,
|
||||
"volume_24h": volume,
|
||||
"score": score,
|
||||
})
|
||||
|
||||
candidates.sort(key=lambda x: x["score"], reverse=True)
|
||||
return candidates[:5]
|
||||
|
||||
|
||||
# ============== 主控制器 ==============
|
||||
def run_cycle():
|
||||
load_env()
|
||||
trader = BinanceTrader()
|
||||
picker = CoinPicker(trader.exchange)
|
||||
positions = load_positions()
|
||||
|
||||
log(f"当前持仓数: {len(positions)} | 最大允许: {MAX_POSITIONS} | DRY_RUN={DRY_RUN}")
|
||||
|
||||
# 1. 检查现有持仓(止盈止损)
|
||||
tickers = trader.fetch_tickers()
|
||||
new_positions = []
|
||||
for pos in positions:
|
||||
sym = pos["symbol"]
|
||||
qty = float(pos["quantity"])
|
||||
cost = float(pos["avg_cost"])
|
||||
# ccxt tickers 使用 slash 格式,如 PENGU/USDT
|
||||
sym_ccxt = sym.replace("USDT", "/USDT") if "/" not in sym else sym
|
||||
ticker = tickers.get(sym_ccxt)
|
||||
if not ticker:
|
||||
new_positions.append(pos)
|
||||
continue
|
||||
|
||||
price = float(ticker["last"])
|
||||
pnl_pct = (price - cost) / cost
|
||||
log(f"监控 {sym} | 现价 ${price:.8f} | 成本 ${cost:.8f} | 盈亏 {pnl_pct:+.2%}")
|
||||
|
||||
action = None
|
||||
if pnl_pct <= STOP_LOSS_PCT:
|
||||
action = "STOP_LOSS"
|
||||
elif pnl_pct >= TAKE_PROFIT_2_PCT:
|
||||
action = "TAKE_PROFIT_2"
|
||||
elif pnl_pct >= TAKE_PROFIT_1_PCT:
|
||||
sold_pct = float(pos.get("take_profit_1_sold_pct", 0))
|
||||
if sold_pct == 0:
|
||||
action = "TAKE_PROFIT_1"
|
||||
|
||||
if action == "STOP_LOSS":
|
||||
trader.create_market_sell_order(sym, qty)
|
||||
log(f"🛑 {sym} 触发止损,全部清仓")
|
||||
continue
|
||||
|
||||
if action == "TAKE_PROFIT_1":
|
||||
sell_qty = qty * 0.5
|
||||
trader.create_market_sell_order(sym, sell_qty)
|
||||
pos["quantity"] = qty - sell_qty
|
||||
pos["take_profit_1_sold_pct"] = 50
|
||||
pos["updated_at"] = datetime.now(timezone.utc).isoformat()
|
||||
log(f"🎯 {sym} 触发止盈1,卖出50%,剩余 {pos['quantity']:.4f}")
|
||||
new_positions.append(pos)
|
||||
continue
|
||||
|
||||
if action == "TAKE_PROFIT_2":
|
||||
trader.create_market_sell_order(sym, float(pos["quantity"]))
|
||||
log(f"🚀 {sym} 触发止盈2,全部清仓")
|
||||
continue
|
||||
|
||||
new_positions.append(pos)
|
||||
|
||||
# 2. 开新仓
|
||||
if len(new_positions) < MAX_POSITIONS:
|
||||
candidates = picker.scan()
|
||||
held_bases = {p["base_asset"] for p in new_positions}
|
||||
total_usdt = trader.get_balance("USDT")
|
||||
available_usdt = total_usdt
|
||||
open_slots = MAX_POSITIONS - len(new_positions)
|
||||
position_size = calculate_position_size(total_usdt, available_usdt, open_slots)
|
||||
|
||||
log(f"总资产 USDT: ${total_usdt:.2f} | 策略上限({CAPITAL_ALLOCATION_PCT:.0%}): ${total_usdt*CAPITAL_ALLOCATION_PCT:.2f} | 每仓建议金额: ${position_size:.2f}")
|
||||
|
||||
for cand in candidates:
|
||||
if len(new_positions) >= MAX_POSITIONS:
|
||||
break
|
||||
base = cand["base"]
|
||||
if base in held_bases:
|
||||
continue
|
||||
if position_size <= 0:
|
||||
log("策略资金已用完或余额不足,停止开新仓")
|
||||
break
|
||||
|
||||
symbol = cand["symbol"]
|
||||
order = trader.create_market_buy_order(symbol, position_size)
|
||||
avg_price = float(order.get("price") or cand["price"])
|
||||
qty = position_size / avg_price if avg_price else 0
|
||||
|
||||
new_positions.append({
|
||||
"account_id": "binance-main",
|
||||
"symbol": symbol.replace("/", ""),
|
||||
"base_asset": base,
|
||||
"quote_asset": "USDT",
|
||||
"market_type": "spot",
|
||||
"quantity": qty,
|
||||
"avg_cost": avg_price,
|
||||
"opened_at": datetime.now(timezone.utc).isoformat(),
|
||||
"updated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"note": "Auto-trader entry",
|
||||
})
|
||||
held_bases.add(base)
|
||||
available_usdt -= position_size
|
||||
position_size = calculate_position_size(total_usdt, available_usdt, MAX_POSITIONS - len(new_positions))
|
||||
log(f"📈 新开仓 {symbol} | 买入价 ${avg_price:.8f} | 数量 {qty:.2f}")
|
||||
|
||||
save_positions(new_positions)
|
||||
log("周期结束,持仓已保存")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
run_cycle()
|
||||
except Exception as e:
|
||||
log(f"❌ 错误: {e}")
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user