refactor: decouple Coin Hunter from Hermes for cross-platform usage
- Add unified coinhunter_shim.py that accepts subcommands (pre/gate/review/rotate-log) - Update SKILL.md gate pseudocode to read optional ~/.coinhunter/platform.json - Split cron/setup examples into Hermes and OpenClaw variants across docs - Introduce platform.json schema in user-data-layout.md - Remove stale auto_trader.py/run_trader.sh references from auto-trading-guide.md - Keep legacy shims as backward-compatible wrappers
This commit is contained in:
82
SKILL.md
82
SKILL.md
@@ -76,6 +76,12 @@ Read `references/short-term-trading-framework.md` before every active decision p
|
||||
|
||||
## Auto-trading architecture
|
||||
|
||||
Install the executable CLI first:
|
||||
```bash
|
||||
pipx install coinhunter
|
||||
# or: pip install coinhunter
|
||||
```
|
||||
|
||||
| CLI Command | Purpose |
|
||||
|-------------|---------|
|
||||
| `coinhunter exec` | Order execution layer (buy / flat / rotate / hold) |
|
||||
@@ -92,7 +98,7 @@ Read `references/short-term-trading-framework.md` before every active decision p
|
||||
When model cost or quota is tight, do not let every cron run perform full analysis from scratch.
|
||||
|
||||
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.
|
||||
1. Attach a lightweight Python `script` to the cron job (under your platform's scripts directory, e.g. `~/.hermes/scripts/` or `~/.openclaw/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)
|
||||
@@ -105,10 +111,10 @@ Recommended pattern:
|
||||
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>`
|
||||
- only when `should_analyze=true` and no run is already queued, trigger your platform's cron job (e.g. `hermes cron run <job_id>` or `openclaw trigger <job_id>`)
|
||||
- store a `run_requested_at` marker in `~/.coinhunter/state/precheck_state.json` and clear it when the analysis acknowledges completion
|
||||
|
||||
This pattern preserves Telegram auto-delivery from Hermes cron while reducing model wakeups to trigger-only events.
|
||||
This pattern preserves auto-delivery from your platform's cron system while reducing model wakeups to trigger-only events.
|
||||
|
||||
### 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.
|
||||
@@ -214,31 +220,51 @@ if __name__ == "__main__":
|
||||
print(json.dumps(result))
|
||||
```
|
||||
|
||||
#### 4. Hermes cron job configuration
|
||||
Attach the precheck script as the `script` field of the cron job so its JSON output is injected into the prompt:
|
||||
#### 4. Cron job configuration
|
||||
Attach the precheck script as the `script` field of the cron job so its JSON output is injected into the prompt.
|
||||
|
||||
**Hermes example:**
|
||||
```json
|
||||
{
|
||||
"id": "coinhunter-trade",
|
||||
"schedule": "*/15 * * * *",
|
||||
"prompt": "You are Coin Hunter. If the injected context says should_analyze=false, respond with exactly [SILENT] and do nothing. Otherwise, read ~/.coinhunter/positions.json, run the scientific checklist, decide HOLD/SELL/REBALANCE/BUY, and execute via the `coinhunter` CLI. After finishing, run `coinhunter pre --ack` to clear the trigger.",
|
||||
"script": "coinhunter_precheck.py",
|
||||
"script": "coinhunter_shim.py pre",
|
||||
"deliver": "telegram",
|
||||
"model": "kimi-for-coding"
|
||||
}
|
||||
```
|
||||
|
||||
Add an `--ack` handler to the precheck script (or a separate ack script) that sets `run_acknowledged_at` and clears `run_requested_at` so the gate does not re-fire until the next true trigger.
|
||||
**OpenClaw example:**
|
||||
```json
|
||||
{
|
||||
"id": "coinhunter-trade",
|
||||
"schedule": "*/15 * * * *",
|
||||
"prompt": "You are Coin Hunter. If the injected context says should_analyze=false, respond with exactly [SILENT] and do nothing. Otherwise, read ~/.coinhunter/positions.json, run the scientific checklist, decide HOLD/SELL/REBALANCE/BUY, and execute via the `coinhunter` CLI. After finishing, run `coinhunter pre --ack` to clear the trigger.",
|
||||
"script": "coinhunter_shim.py pre",
|
||||
"deliver": "webhook"
|
||||
}
|
||||
```
|
||||
|
||||
Acknowledge completion by running `coinhunter pre --ack` so the gate clears `run_requested_at` and does not re-fire until the next true trigger.
|
||||
|
||||
#### 5. External gate (optional, for even lower cost)
|
||||
If you want to run the precheck every 5 minutes without waking Hermes at all:
|
||||
|
||||
External gate pseudocode (run from `~/.hermes/scripts/`):
|
||||
External gate pseudocode (run from your platform's scripts directory):
|
||||
```python
|
||||
import fcntl, os, subprocess, json, sys
|
||||
|
||||
LOCK_PATH = os.path.expanduser("~/.coinhunter/state/external_gate.lock")
|
||||
PRECHECK = os.path.expanduser("~/.hermes/scripts/coinhunter_precheck.py")
|
||||
JOB_ID = "coinhunter-trade"
|
||||
PLATFORM_PATH = os.path.expanduser("~/.coinhunter/platform.json")
|
||||
|
||||
# Load platform config if it exists; default to Hermes behavior
|
||||
platform = {"cron_command": ["hermes", "cron", "run"]}
|
||||
if os.path.exists(PLATFORM_PATH):
|
||||
platform.update(json.load(open(PLATFORM_PATH)))
|
||||
|
||||
cron_command = platform.get("cron_command", ["hermes", "cron", "run"])
|
||||
|
||||
with open(LOCK_PATH, "w") as f:
|
||||
try:
|
||||
@@ -246,22 +272,37 @@ with open(LOCK_PATH, "w") as f:
|
||||
except BlockingIOError:
|
||||
sys.exit(0) # another instance is running
|
||||
|
||||
result = json.loads(os.popen(f"python {PRECHECK}").read())
|
||||
result = json.loads(os.popen("coinhunter pre").read())
|
||||
if result.get("should_analyze"):
|
||||
# Trigger Hermes cron only if not already requested
|
||||
# Trigger platform cron only if not already requested
|
||||
state_path = os.path.expanduser("~/.coinhunter/state/precheck_state.json")
|
||||
state = json.load(open(state_path))
|
||||
if not state.get("run_requested_at"):
|
||||
subprocess.run(["hermes", "cron", "run", JOB_ID], check=False)
|
||||
subprocess.run([*cron_command, JOB_ID], check=False)
|
||||
```
|
||||
|
||||
System crontab entry:
|
||||
```cron
|
||||
*/5 * * * * /usr/bin/python3 /home/user/.hermes/scripts/coinhunter_external_gate.py >> /home/user/.coinhunter/logs/external_gate.log 2>&1
|
||||
*/5 * * * * /usr/bin/env coinhunter gate >> /home/user/.coinhunter/logs/external_gate.log 2>&1
|
||||
```
|
||||
|
||||
With this setup, the model is only invoked when a material market change occurs—preserving intelligence while cutting routine cost by 80-95%.
|
||||
|
||||
### Troubleshooting common precheck errors
|
||||
When `coinhunter pre` fails with `status: deep_analysis_required` and `reasons: ["precheck-error"]`, inspect the `details` field and apply these known fixes:
|
||||
|
||||
1. **`'PosixPath' object has no attribute 'env_file'`**
|
||||
- Location: inside the installed `coinhunter` package (`src/coinhunter/services/market_data.py` in the PyPI source)
|
||||
- Cause: `load_env_file(ENV_FILE)` is passed a `Path` object, but `load_env_file()` expects either a `RuntimePaths` dataclass or no arguments.
|
||||
- Fix: Update `coinhunter` to the latest version from PyPI. If the bug persists, patch the installed package and submit an issue to the `coinhunter` project.
|
||||
|
||||
2. **`name 'BASE_PN_L_TRIGGER_PCT' is not defined`**
|
||||
- Location: inside the installed `coinhunter` package (`src/coinhunter/services/adaptive_profile.py` in the PyPI source)
|
||||
- Cause: Typo `BASE_PN_L_TRIGGER_PCT` instead of `BASE_PNL_TRIGGER_PCT`.
|
||||
- Fix: Update `coinhunter` to the latest version from PyPI. If the bug persists, patch the installed package and submit an issue to the `coinhunter` project.
|
||||
|
||||
After updating, rerun `coinhunter pre` to verify the gate clears before executing the trading decision.
|
||||
|
||||
### 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.
|
||||
@@ -272,6 +313,21 @@ The live trading stack must include these safeguards:
|
||||
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.
|
||||
|
||||
## Cross-platform deployment
|
||||
|
||||
Coin Hunter is runtime-agnostic. It works on Hermes, OpenClaw, and any compatible cron-based platform.
|
||||
|
||||
1. **Install the CLI** (same everywhere):
|
||||
```bash
|
||||
pipx install coinhunter
|
||||
```
|
||||
|
||||
2. **Place the shim** in your platform's scripts directory:
|
||||
- Hermes: `~/.hermes/scripts/coinhunter_shim.py`
|
||||
- OpenClaw: `~/.openclaw/scripts/coinhunter_shim.py`
|
||||
|
||||
3. *(Optional)* Create `~/.coinhunter/platform.json` if you want the external gate to use a non-default trigger command. When absent, the gate falls back to Hermes behavior (`hermes cron run`).
|
||||
|
||||
## Safety rules
|
||||
- No leverage/futures when capital < $200.
|
||||
- When capital < $50, concentrate into **1 position only**.
|
||||
|
||||
Reference in New Issue
Block a user