[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6GSBJN5DSAHNT253SAF5RE4":3,"skill-same:01M6GSBJN5DSAHNT253SAF5RE4":96},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":41,"linkOnly":42,"markdownContent":43,"markdownBody":44,"frontMatter":45,"refName":57,"commitSha":58,"skillDirectory":59,"forksCount":60,"repositoryHtmlUrl":61,"repositoryHomepageUrl":6,"ownerHtmlUrl":62,"ownerBlogUrl":63,"ownerDescription":64,"updatedAt":65,"install":66,"resources":79},"01M6GSBJN5DSAHNT253SAF5RE4","binance-onchain-copy-trader",null,"Scaffold for assembling on-chain copy-trading strategies on Binance Agentic Wallet. Wires the\nexisting capabilities — address monitoring, signal subscription, address scoring, token audit,\norder placement, on-chain take-profit\u002Fstop-loss — into one runnable pipeline, and exposes every\nstrategy decision as a hook. Ships no strategy of its own.\nTrigger on: copy trade, copy trading, follow smart money, follow a wallet, mirror trades,\ncopy-trade bot, auto-buy on signal, monitor a wallet and trade, smart money copy trading,\nsignal-driven trading, pick addresses to copy, copy-trade strategy, copy-trade status,\ncopy-trade post-mortem.\nNOT for: single manual trades (use binance-agentic-wallet), signal queries alone\n(binance-trading-signal), address analysis alone (binance-wallet-tracker \u002F binance-leaderboard).","jiayaoqijia\u002Fcryptoskill","jiayaoqijia","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1453879?v=4","01M6GMYTX7Q7S504VC6E756ENR","YQ","01M6GMYV1QKJ1CC75MTTGT9PR0",81,"AGPL-3.0","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fbinance-official-binance-onchain-copy-trader\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"copy trader","binance onchain copy trader","copy","onchain","binance","post-mortem","status","mirror","addresses","hook","as","strategies","scoring","tracker","stop","Wallet","take","auto","use","strategy","monitoring","capabilities","2026-11-10 10:12:30",false,"---\nname: binance-onchain-copy-trader\ndescription: |\n  Scaffold for assembling on-chain copy-trading strategies on Binance Agentic Wallet. Wires the\n  existing capabilities — address monitoring, signal subscription, address scoring, token audit,\n  order placement, on-chain take-profit\u002Fstop-loss — into one runnable pipeline, and exposes every\n  strategy decision as a hook. Ships no strategy of its own.\n  Trigger on: copy trade, copy trading, follow smart money, follow a wallet, mirror trades,\n  copy-trade bot, auto-buy on signal, monitor a wallet and trade, smart money copy trading,\n  signal-driven trading, pick addresses to copy, copy-trade strategy, copy-trade status,\n  copy-trade post-mortem.\n  NOT for: single manual trades (use binance-agentic-wallet), signal queries alone\n  (binance-trading-signal), address analysis alone (binance-wallet-tracker \u002F binance-leaderboard).\nmetadata:\n  version: '0.6.0'\n  requiredCliVersion: '1.9.1'\n  requires:\n    skills:\n      - binance-agentic-wallet\n      - binance-wallet-tracker\n      - binance-leaderboard\n      - binance-trading-signal\n      - query-token-audit\n---\n\n# Binance On-Chain Copy Trader\n\nA scaffold for a copy-trading pipeline. **This skill provides no strategy.** What it provides is:\na capability index, an event contract, an assembly structure, and three strategy hooks. The\nstrategy itself is yours to build and refine.\n\n> ## Read this first\n>\n> **Every risk control, position-management scheme, and parameter value in this skill is a\n> *suggestion* and an *example*. None of it is mandatory, and none of it constitutes a safety\n> guarantee or investment advice.**\n>\n> - The scaffold guarantees only that **it will run the checks you configure**. It does not\n>   guarantee those checks are sufficient to protect your funds. Budget caps, stop-loss distance,\n>   liquidity floors — you choose all of them. Set them wide, leave them out, or switch off the\n>   honeypot block, and the scaffold will do exactly as told.\n> - The three bundled hooks are a **minimal reference implementation that proves the pipeline\n>   runs**. They are not a recommended strategy and carry **no evidence of positive expectancy**.\n>   Running them live as-is means funding an unvalidated strategy with real money.\n> - On-chain transactions are irreversible. Any automated strategy can lose money through market\n>   conditions you did not anticipate, changes in platform behavior, or defects in this scaffold.\n>   **The risk is yours.**\n> - Suggested path: run `dry-run` long enough to matter → read `events.jsonl` and build your own\n>   baseline → switch to `live` with an amount you can afford to lose entirely → tune from there.\n\n## Dependencies\n\nConfirm the following skills are available in your current environment. This skill only\norchestrates; every underlying capability comes from them:\n\n| Skill | Provides | Used here |\n|---|---|---|\n| `binance-agentic-wallet` | Wallet, market orders, limit orders, quota, chain info | `wallet` `market-order` `limit-order` |\n| `binance-wallet-tracker` | Address monitoring, real-time push, group management | `tracker ws` `tracker token\u002Ftx` `tracker group\u002Faddress` |\n| ↳ | Must include the **Connection lifecycle** and **Signal field nullability** sections — this skill's connection-supervision split and its first-push field assumptions depend on them directly | — |\n| `binance-leaderboard` | Trader rankings, address scoring, holder lookup | `leaderboard query\u002Fanalyze\u002Falpha-radar` |\n| `binance-trading-signal` | Smart-money signals, custom strategies, backtests | `signal list` `signal strategy` `signal backtest` |\n| `query-token-audit` | Token security audit | Audit HTTP endpoint |\n| `query-token-info` | *(optional)* Live token price and market data | Only if a hook needs a live price when the event does not carry one |\n\nVerify:\n\n```bash\nbaw --version\nbaw cli-check --required-version \"$(grep -m1 requiredCliVersion SKILL.md | tr -dc '0-9.')\" --json\n#   ↑ the frontmatter `requiredCliVersion` is the single source of truth for the version floor.\n#     Below it, `tracker ws --duration 0` has no keepalive and no reconnect, and the scaffold\n#     refuses to start.\n```\n\nMissing any one of them disables the corresponding stage: without `binance-leaderboard` there is\nno systematic way to pick addresses; without `binance-trading-signal` you cannot create custom\nsignal strategies; without `query-token-audit` there is no audit data and `hard_gate` falls back\nto `require_audit` to decide whether to pass or reject.\n\nInstall source: `https:\u002F\u002Fgithub.com\u002Fbinance\u002Fbinance-skills-hub`\n\n## Getting started\n\nThe order that takes you from nothing to a scored dry-run. Each step points at the section below.\n\n**Note the ordering.** Writing the strategy comes *after* the first dry-run, not before. That is\ndeliberate: the whole premise of this scaffold is that thresholds should come from your own data,\nand before the first run you have none. So the first pass runs the bundled reference hooks\nunchanged — not because they are any good, but because they produce the dataset you need in order\nto write something better.\n\n**1 · Environment check** → see \"Pre-flight checks\"\nConfirm the wallet is CONNECTED, the target chain supports both `market-order` and `limit-order`,\nand that quote-token and gas balances are sufficient. On a chain where `limit-order` is\nunavailable you cannot place on-chain protective orders — accept that before continuing.\n\n**2 · Pick your trigger sources** → see \"Trigger sources\"\nAddress subscription, signal subscription, or both. This determines how you select sources next.\n\n**3 · Select sources**\n- Address source: `leaderboard query` for candidates → `leaderboard analyze` for the 6-dimension\n  score on each (`follow_friendly` is the most relevant dimension here) → write addresses into\n  `addrs.txt`, one per line, `#` for comments, **max 100**\n- Signal source: `signal explore` to browse official strategies \u002F `signal strategy create` to\n  build your own \u002F `signal strategy follow` to subscribe — or just use `--smy` and let the\n  platform's own judgement drive it, with no configuration at all\n\nThe sort dimension materially changes the character of the candidate pool\n(`--sort-by` 0=PnL 20=win rate 30=volume 50=trade count …), and individual dimensions can\nsaturate — over a short period, for instance, many addresses can tie at 100% win rate. Add your\nown secondary criteria to break ties.\n\n**4 · Write the config** → see \"Configuration\"\nThe first run writes an empty template to `$COPYTRADER_HOME` (default `~\u002F.local\u002Fcopytrader`) and\nrefuses to start until every required field is filled, listing exactly which are missing.\nMechanism parameters (budget \u002F per-trade size \u002F concurrency \u002F gas floor) are separate from\n`policy`, which is passed through to your hooks. **Leave `mode` as `dry-run`.**\n\nThe values here are decisions, not defaults to be guessed — `budget_usd` in particular should be\nan amount whose total loss is acceptable, because that is the number you will be asked to\nacknowledge at step 9.\n\n**5 · Dry-run with the bundled hooks unchanged**\n```bash\ncd \u003Cskill-dir>\u002Fscripts && python3 copytrader.py\n```\nDo not edit the hooks yet. What ships filters almost nothing (direction and freshness only), which\nmakes it a poor strategy but a good instrument: it lets through a broad sample so you can see what\nthe stream actually contains before you start rejecting things.\n\n**6 · Decide whether the plumbing works**\n```bash\ntail -f $COPYTRADER_HOME\u002Fcopytrader.log\n```\nCheck:\n- the startup log's `sources` and `policy` match what you intended\n- `events.jsonl` is being written, and the `decision` distribution is sane — are the rejection\n  reasons the ones you wanted?\n- passing events have values for `lag_s`, `tax`, `audit_risk`, `liquidity`, `price` — a missing\n  value means some upstream call returned nothing\n- `conn_seq` is not climbing fast (frequent reconnects mean an unstable stream)\n- `outcomes.jsonl` starts filling in once the first horizon elapses\n- `state.json`'s `deployed` stays at 0 under dry-run\n\nThis step is about the pipeline, not the strategy. Fix anything here before reading meaning into\nthe data.\n\n**7 · Now write your strategy** → see \"Strategy hooks\" and \"Scoring decisions without spending money\"\nWith a dataset in hand, edit the three functions in the `══`-delimited block at the top of\n`scripts\u002Fcopytrader.py`: `should_enter` \u002F `size_position` \u002F `exit_plan`.\n\nJoin `events.jsonl` and `outcomes.jsonl` on `key` and let that decide your thresholds. Every gate\nyou add should be one you can point at in the data — and you should be able to see, in the\n`decision` distribution, exactly what it rejected. Which parameters your hooks read is up to you;\nput them in the `policy` section of `config.json` and they arrive verbatim.\n\n**8 · Iterate**\nChange hooks → re-run → score again. **This all works in dry-run**, which is the point: outcome\nsampling does not need a fill, so a strategy can be evaluated from recorded data instead of from\nreal money. Accumulating a usable sample size is otherwise the expensive part.\n\nResist concluding early. A handful of scored decisions tells you nothing, and a mean carried by\none or two outliers tells you nothing either.\n\n**9 · Switch to live**\nSet `mode` to `live` **and** acknowledge the amount being risked — live mode refuses to start\nuntil the acknowledgement file contains the current `budget_usd`:\n\n```bash\necho \u003Cbudget_usd> > $COPYTRADER_HOME\u002FI_UNDERSTAND_THE_RISK\n```\n\n**The operator has to confirm the amount; an agent may write the file once they have.** What the\ngate is for is that the decision was made, and made about this specific number — not that a human\ntyped the command. So the natural flow is: the agent states the budget and what a full loss of it\nwould mean, the operator confirms, the agent writes the file and starts the run.\n\nWhy the amount rather than a bare `touch`: it cannot be inherited by copying someone else's\nruntime directory, the number has to come from whoever decided it, and **raising `budget_usd`\nlater invalidates the acknowledgement** — more money at risk deserves a fresh decision rather\nthan a stale one.\n\nBefore this point you should already have: run dry-run long enough to accumulate a meaningful\nsample, scored those decisions from `outcomes.jsonl` rather than from intuition, and concluded\nthat losing `budget_usd` in full is acceptable.\n\n**Dry-run does not record positions, so the budget and concurrency guardrails never fire — the\ndry-run pass count will therefore be higher than the number of positions live would actually\nopen.** Do not size live from a dry-run pass rate.\n\n## Capability map\n\nEvery stage of the pipeline maps to an existing capability. **The tables below are an index of\nwhere to look; treat each skill's own documentation and `--help` as authoritative for parameters.**\n\n### Source selection — pick addresses for the address source; pick or build strategies for the signal source\n\n| Capability | Command | Returns | Key parameters |\n|---|---|---|---|\n| Trader ranking | `baw leaderboard query` | address · winRate · realizedPnl · realizedPnlPercent · totalVolume · totalTxCnt · buyTxCnt · tags · addressLabel | `-c` chain · `-p` 7d\u002F30d\u002F90d · `-t` ALL\u002FKOL\u002FMPC · `--sort-by` 0=PnL 20=win rate 30=volume 50=trades 60=activity 70=rate 80=token count · `--page` · `--size` (≤20) |\n| Single-address score | `baw leaderboard analyze` | 6-dimension score (winrate \u002F stability \u002F drawdown \u002F tags \u002F pnl \u002F **follow_friendly**) plus an AI archetype | `-c` · `-a` address · `-p` · `--top-n` (≤5000) |\n| Reverse lookup by holding | `baw leaderboard alpha-radar` | Addresses holding a given token | `-c` · `-t` comma-separated token addresses · `-m` minimum hits · `-p` |\n| Token-level monitoring | `baw tracker token` | Recent token activity | `-c` · `-g` group · `--tag-type` kol\u002Fsmy · `--token-size` · `--period` 1m\u002F5m\u002F1h\u002F4h\u002F24h · `--filter-risk` |\n| Trade-level monitoring | `baw tracker tx` | Individual trades | same as above |\n| Followed addresses | `baw tracker follow` | The current follow list (read-only) | `-c` |\n| Group management | `baw tracker group` \u002F `address` | Create groups, bulk import, label, link | see wallet-tracker docs |\n\n### Trigger sources — two peer real-time subscriptions\n\nBoth go through `baw tracker ws` and both are WebSocket push with latency of the same order.\nThe difference is **who decides what is worth looking at**: with the address source you name the\nwallets; with the signal source the platform (or a strategy you built) decides. Run either alone\nor both together (`sources: [\"address\",\"signal\"]`).\n\n#### A · Address subscription — you pick the wallets, it pushes every trade they make\n\n| Command | Event semantics |\n|---|---|\n| `baw tracker ws --address-list \u003Cfile> -c \u003Cchain>` | Every on-chain trade by the listed addresses, **max 100 addresses** |\n| `baw tracker ws --address \u003Caddr> -c \u003Cchain>` | A single address |\n| `baw tracker ws --following -c \u003Cchain>` | The current follow list; requires login, mutually exclusive with the other flags |\n\n- **How to select**: `leaderboard query\u002Fanalyze\u002Falpha-radar`, plus `tracker group\u002Faddress` to build groups\n- **Event granularity**: one trade, one event; no re-pushes\n- **Direction**: `tradeSideCategory` — buys `{11,19}`, sells `{21,29}`\n- **Chains**: `-c` applies; single chain\n- **Entry price**: the event carries `tokenPrice` (the counterparty's actual fill price)\n- **Delivery latency**: measure it yourself. Expect a median on the order of seconds but a heavy\n  tail (P90 can reach minutes). Record real latency from the event timestamp rather than assuming.\n\n#### B · Signal subscription — the platform or your strategy decides, and pushes the verdict\n\n| Command | Event semantics |\n|---|---|\n| `baw tracker ws --smy` | Smart-money signals (multi-address consensus). **All chains; `-c` has no effect** |\n| `baw tracker ws --kol -c \u003Cchain>` | KOL-level events |\n| `baw tracker ws --wallet BSC,SOL,BASE,ETH` | Chain-level wallet activity, comma-separated |\n\n- **How to select**: `signal explore` to browse official strategies, `signal strategy create\u002Ffollow`\n  to build or subscribe to custom ones (meme-rush \u002F fomo-call), `signal backtest` to backtest\n- **Event granularity**: **the same `signalId` is pushed repeatedly with state updates** — on the\n  order of tens to hundreds of pushes per signal. Deciding \"this is a new signal\" requires\n  deduping by `signalId`\n- **Signal-only fields**: `smartMoneyCount` (how many smart-money addresses agree) · `exitRate`\n  (share already exited) · `maxGain` · `status`\n- **`status` semantics**: `valid`\u002F`active` live · `timeout` expired (one push at T+120min after\n  the trigger) · `outDecline` · `exitRate`\n- **Chains**: all-chain push; filter by `chainId` yourself\n- **Entry price**: `currentPrice` (often `null`) or `alertPrice` (the historical price at trigger\n  time — **not a currently tradable price**)\n- **Delivery latency**: measure it yourself, and mind the methodology — you **must take the\n  minimum lag per `signalId` and count only genuine first pushes**. Otherwise re-pushes turn \"the\n  signal's current age\" into \"latency\" and the result comes out orders of magnitude too high.\n\n#### Choosing between them\n\n| | Address source | Signal source |\n|---|---|---|\n| Who decides what to watch | You (address selection) | Platform verdict \u002F your custom strategy |\n| Meaning of one event | One person's single trade | Consensus across several addresses |\n| Coverage | Bounded by the 100-address cap | Platform-wide, all chains |\n| Dedupe required | No | **Yes** (by `signalId`) |\n| Timestamp field | `ts` | `signalTriggerTime` |\n| Event density | Depends on how active your chosen addresses are, and how many | Depends on platform verdicts and is unevenly distributed across chains — subscribing to one chain may mean long stretches with no events |\n\nShared parameter: `--duration \u003Csec>` (0 or omitted = unlimited). Each source occupies one reader\nthread in the scaffold; events are normalized by `norm_address()` \u002F `norm_signal()` and merged\ninto a single queue.\n\n### Signal query and strategy management (REST, not push)\n\n> The **real-time path for smart-money signals is `tracker ws --smy`** in the table above. This\n> group is REST query and strategy management — for backfill, filtering, building custom\n> strategies, and backtesting. It has nothing to do with latency.\n\n| Capability | Command | Key parameters |\n|---|---|---|\n| Signal feed (backfill) | `baw signal list` | `-c` chain · `-s` all\u002Fuser\u002Fmeme\u002Fsmart-money · `--time-range` 5m\u002F1h\u002F24h (filters on `signalTriggerTime`) · `--sort-by` time\u002FmaxGain · `-n` (≤100) |\n| Custom strategies | `baw signal strategy create\u002Fupdate\u002Fdelete\u002Ffollow\u002Funfollow\u002Flist\u002Flist-followed` | `-c` · `-t` meme-rush\u002Ffomo-call · `--job-id` · `--config` |\n| Backtests | `baw signal backtest list\u002Fdetail\u002Fretry\u002Fschedule` | `--interval` 4H\u002F6H\u002F12H\u002F24H\u002FOFF |\n| Backtest credits | `baw signal credits` | — |\n| Official strategy hall | `baw signal explore` | — |\n\n`signal list` returns fields from the same source as `tracker ws --smy` pushes (`signalId` values\nline up), but neither is a superset of the other.\n\n### Risk control and execution\n\n> The capabilities below are **available tools**. Whether and how you combine them is decided by\n> your hooks and your config. This skill does not mandate any particular check — it only\n> guarantees that the checks you asked for run at the right moment.\n\n| Capability | Command \u002F endpoint |\n|---|---|\n| Token audit | `POST https:\u002F\u002Fweb3.binance.com\u002Fbapi\u002Fdefi\u002Fv1\u002Fpublic\u002Fwallet-direct\u002Fsecurity\u002Ftoken\u002Faudit`, body `{binanceChainId, contractAddress, requestId}`. Returns `hasResult` `isSupported` `riskLevel` `extraInfo.buyTax\u002FsellTax` `riskItems[].details[].isHit` |\n| Market data | `GET ...\u002Fbuw\u002Fwallet\u002Fmarket\u002Ftoken\u002Fdynamic\u002Finfo\u002Fai?chainId=&contractAddress=` → `price` `liquidity` `holders` `volume24h` |\n| Quote | `baw market-order quote --fromTokenQty --fromToken --toToken --binanceChainId --slippage` |\n| Market order | `baw market-order swap` (same parameters plus `--mev` `--gasLevel`) → returns `orderId` |\n| Order lookup | `baw market-order list` → `status` `toTokenActualQty` `txHash` |\n| Limit order | `baw limit-order buy\u002Fsell --triggerPrice --fromTokenQty --fromToken --toToken --binanceChainId --slippage --mev --gasLevel` |\n| Cancel \u002F list | `baw limit-order cancel --strategyId` · `baw limit-order list` |\n| Guardrail readings | `baw wallet balance` · `left-quota` · `tx-lock` · `settings` · `chains` |\n\n## Event schema\n\nBoth sources are normalized by `norm_address()` \u002F `norm_signal()` into one structure. Hooks only\never see this:\n\n```python\n{\n  \"src\":   \"address\" | \"signal\",\n  \"key\":   dedupe key (address stream = txHash; signal stream = \"sig:\" + signalId),\n  \"ca\":    token contract address,\n  \"token\": token name,\n  \"price\": entry reference price (address stream = counterparty fill price `tokenPrice`;\n           signal stream = `currentPrice` or `alertPrice`),\n  \"ts\":    event time (epoch seconds) — time.time() - ts is the delivery latency,\n  \"chain\": chain ID,\n  \"side\":  11\u002F19 = buy, 21\u002F29 = sell (always 11 on the signal stream),\n  \"who\":   source identity (address stream = wallet label; signal stream = \"SMY×N\"),\n  \"usd\":   USD size of the counterparty's trade,\n  \"risk\":  tokenRiskLevel,\n  \"top10\": top-10 holder concentration,\n  \"tags\":  token tag array,\n  \"extra\": source-specific fields\n}\n```\n\n`extra` differs by source:\n\n| Source | `extra` contents |\n|---|---|\n| address | `addr` |\n| signal | `signalId` `status` `smy` (consensus count) `exitRate` `liq` `entry_liq` `holders` `is_alpha` `launch_ms` `mcap` `sig_seq` |\n\nFor the **full set of raw push fields** (including those dropped during normalization) see the\nfield tables in `binance-wallet-tracker`. Extend the `norm_*` functions to carry more of them\ninto `extra` when you need them.\n\n### Signal stream: field availability on first push vs re-push\n\n**Know this before you write any strategy.** `--smy` is a state stream, not an event stream — the\nsame `signalId` is pushed repeatedly throughout its lifetime, and **the first push and the\nre-pushes carry different fields**. A strategy can only use fields that are present on the first\npush, because the decision has to be made then.\n\nThe authoritative definition lives in the **Signal field nullability** section of\n`binance-wallet-tracker\u002Freferences\u002Fcli.md`. The table below is how that lands at the assembly\nlayer:\n\n| Field | First push | Usable for an entry decision? |\n|---|---|---|\n| `signalId` `ticker` `chainId` `contractAddress` | carried | Yes |\n| **`signalTriggerTime`** | **carried** | **Yes — compute delivery freshness from it** |\n| `alertPrice` `alertMarketCap` | carried | Yes (but note: historical price at trigger time, not a tradable price) |\n| `alertLiquidity` `entryLiquidity` | carried | Yes |\n| `top10` `holders` `smartMoneyCount` `isAlpha` `launchTime` | carried | Yes |\n| `status` | **usually `null`** | **No — see note 1** |\n| `exitRate` `maxGain` `currentPrice` | **usually `null`** | **No — see note 2** |\n\nNotes:\n\n1. **A `status` gate may only reject explicit bad values; a missing value must pass.** `status` is\n   usually `null` on the first push (the lifecycle states `timeout` \u002F `outDecline` \u002F `exitRate`\n   are stamped on later pushes). Writing `if st not in (\"valid\",\"active\")` silently drops almost\n   every genuine first push, **and the symptom is indistinguishable from \"there are no signals on\n   this chain\"**, which makes it very hard to diagnose. Correct form:\n\n   ```python\n   if st is not None and st not in (\"valid\", \"active\"):\n       return False, f\"status={st}\"\n   ```\n\n2. **Do not use `exitRate` \u002F `maxGain` \u002F `currentPrice` as entry conditions.** They describe how a\n   signal evolved *after* it fired; the server has not computed them at first-push time. A\n   threshold gate on them never fires on a first push and only misjudges older signals you joined\n   mid-life. Use them for exit logic or post-hoc correlation analysis instead — the fields are\n   still written to `events.jsonl` in full.\n\n3. **Do not place orders against `alertPrice` as if it were tradable.** It is the historical price\n   at trigger time; combined with delivery latency, using it as a fill price books an order that\n   cannot fill. This scaffold treats it purely as a **reference price handed to the hooks**, while\n   protective-order triggers are always derived from the real entry price computed as\n   `usd \u002F actual filled quantity`. Keep the two apart. If a hook needs a live price, query market\n   data (`query-token-info`) and skip when unavailable.\n\n4. **You do not need a market-data call for liquidity** — `alertLiquidity` is present on the first\n   push, and market data often has no index for newly launched tokens, making it less reliable\n   than the event's own field. Also note the signal source already filters on liquidity, so\n   **a liquidity floor on the signal stream is close to a no-op**; do not expect it to carry your\n   filtering.\n\n5. **Expired re-pushes must be caught by a freshness gate, not by `status`.** The `status=timeout`\n   expiry notice always arrives at T+120min after the trigger; it carries `status` but its\n   `signalTriggerTime` is old. The two gates back each other up: `status` catches explicit bad\n   values, freshness catches anything stale in time.\n\n## Assembly structure\n\n```\nws_reader(source)          one thread per source; timestamps and enqueues only, never blocks\n      ↓ queue\nworker × N\n      ↓\n  norm_* ─────────────► normalized event `ev`\n      ↓\n  should_enter(ev, ctx)    ← hook ①  ctx.audit \u002F liquidity are still None here\n      ↓ pass\n  gate_ok()                mechanism guardrails: budget \u002F positions \u002F gas \u002F tx-lock \u002F quota \u002F STOP\n      ↓\n  audit() ∥ token_market()  fetch audit and market data concurrently, completing ctx\n      ↓\n  hard_gate(ctx)            mechanism-forced check: audit has a result + honeypot (configurable)\n      ↓\n  should_enter(ev, ctx)    ← hook ① again, now with audit and liquidity\n      ↓ pass\n  size_position(ev, ctx)   ← hook ②  returns a USD amount\n      ↓\n  market-order swap → actual_qty() reads toTokenActualQty from market-order list\n      ↓\n  exit_plan(ev, ctx, entry, qty) ← hook ③  returns [(trigger_price, qty, slippage), ...]\n      ↓\n  place_protection()        places limit-order sells in the returned order\n      ↓\n  reconcile()               periodic: once any protective order fills, re-place against the\n                            actual remaining balance\n```\n\n### Why it is assembled this way\n\nThree non-obvious choices in the pipeline, each resting on an interface contract. Confirm the\ncontract still holds before changing them:\n\n| Choice | Contract it rests on |\n|---|---|\n| Filled quantity comes from `market-order list`, not from polling the wallet balance | `market-order swap` returns `orderId` and **neither a txHash nor a filled quantity**; the quantity is `toTokenActualQty` in `market-order list` |\n| `exit_plan` can express a stop-loss | `limit-order sell` accepts a `triggerPrice` **below market** and stays `status: WORKING` rather than filling immediately |\n| `ws_reader` **only restarts at the process level** | Connection-level care is built into `tracker ws --duration 0` (PING keepalive + auto-reconnect + backoff); the required CLI version is in the frontmatter's `requiredCliVersion`. The **Connection lifecycle** section of `binance-wallet-tracker` explicitly asks callers not to add a second layer — an outer rotation would kill a healthy connection, and an outer watchdog would abort a reconnect the CLI is already backing off for |\n\nTwo more choices affect how readings are interpreted: `ws_reader` records `conn_uptime_s` so\nserver-side delay can be told apart from post-reconnect replay; and the reader thread makes no\nblocking calls, because otherwise processing time accumulates and inflates the arrival timestamps\nof later events.\n\n## Strategy hooks\n\n> The three hooks are **where you write your strategy**. What ships in the repository is only an\n> example that makes the pipeline run — every judgement and every threshold in it should be\n> replaced by whatever your own analysis shows.\n\nThe three functions sit at the top of `scripts\u002Fcopytrader.py`; the mechanism layer never touches\nthem. Signatures:\n\n```python\nshould_enter(ev, ctx) -> (bool, reason)\nsize_position(ev, ctx) -> float            # USD; the mechanism layer then clamps to\n                                           # min(value, position_usd, remaining budget)\nexit_plan(ev, ctx, entry_price, qty) -> [(trigger_price, sell_qty, slippage_pct), ...]\n```\n\n`ctx` contents:\n\n| Key | Meaning |\n|---|---|\n| `audit` | Raw audit response (`None` on the first hook call) |\n| `liquidity` | Liquidity from market data (`None` on the first call; the signal stream can fall back to `extra.liq`) |\n| `price` | Entry reference price |\n| `positions` | Current positions dict |\n| `deployed` | USD deployed so far |\n| `cfg` | Full config |\n| `policy` | The `policy` section of `config.json`, **passed through verbatim; the mechanism layer does not interpret its keys** |\n\n`should_enter` is called **twice**: once **before spending anything on audit and market data**\n(only the event's own fields are available), and once **after both are ready**. Put cheap\njudgements in the first call and anything that needs audit data in the second.\n\nHelper: `audit_tax(a)` pulls `buyTax + sellTax` out of an audit response.\n\n## Mechanism guardrails\n\n**Two different things.** *Running* a guardrail is the mechanism layer's job and hooks cannot get\naround it; the *values and switches* are your decision.\n\n| | Who decides | Note |\n|---|---|---|\n| When a check runs and who runs it | The scaffold | e.g. \"check the budget before every entry\" cannot be switched off |\n| **What threshold a check uses, and whether it is enabled** | **You** | How large `budget_usd` is, whether `block_honeypot` stays on — the scaffold executes whatever the config says |\n| What to buy, how much, and how to exit once a check passes | **Your hooks** | The mechanism layer only clamps ceilings; it does not pick instruments |\n\nSo what follows is a **suggested set of guardrails, not a safety guarantee**. A config with\n`budget_usd: 1000000` and the honeypot block switched off will run perfectly happily.\n\n### The guardrail list\n\n| Item | Behavior |\n|---|---|\n| Budget | Cumulative deployment never exceeds `budget_usd`; `size_position`'s return value is clamped |\n| Per trade | Never exceeds `position_usd` |\n| Concurrency | Never exceeds `max_positions` |\n| Gas | Stops opening when the native balance is below `gas_floor_native`; **also stops if the balance cannot be read** |\n| Serialization | No orders while `tx-lock` reports LOCKED |\n| Quota | No orders when `left-quota` is insufficient |\n| Same token | A token already held is not opened again |\n| Single instance | pidfile lock; a second start exits immediately |\n| Gates | `STOP` halts new entries (existing protective orders are untouched); `KILL` exits the process |\n| Mode | Under `mode: dry-run` no order request is issued at all |\n| Live acknowledgement | `mode: live` refuses to start unless `$COPYTRADER_HOME\u002FI_UNDERSTAND_THE_RISK` contains the current `budget_usd`. Cannot be inherited by copying a runtime directory, and raising the budget invalidates it |\n\n**Switching `mode` from `dry-run` to `live` requires the operator's explicit decision about a\nspecific amount**, and the scaffold enforces that with the acknowledgement file above rather than\ntrusting a config edit alone. An agent may write the file after the operator confirms the amount.\n\n### The connection-supervision split\n\n**Connection-level care belongs to the CLI; process-level care belongs to this scaffold.** Do not\ndo both.\n\n| Layer | Owner | What it does |\n|---|---|---|\n| Connection | **CLI** | `tracker ws --duration 0` has it built in: a 30s application-level PING, auto-reconnect and re-SUBSCRIBE on `onclose`, exponential backoff (reset on any received push) |\n| Process | **This scaffold** | Restarts the child process only when it actually exits (fixed short delay, `proc_restart_sec`), and writes a `state[\"stream_alarm\"]` |\n\nWhy they must not be stacked (the **Connection lifecycle** section of `binance-wallet-tracker`\nstates this explicitly):\n\n- an outer \"active rotation\" periodically kills a connection the CLI was maintaining perfectly well\n- an outer \"silence watchdog\" force-kills the child while the CLI is mid-backoff, aborting a pending reconnect\n- two nested backoffs make the real reconnect interval unpredictable\n\n`--duration N > 0` is **different semantics**: a single connection that rejects on disconnect and\ndoes not reconnect. Use it for one-off sampling, never for a long-running process.\n\n> **The version floor is hard.** Built-in keepalive is a precondition of this scaffold. Below the\n> required CLI version, `--duration 0` has neither keepalive nor reconnect, and the scaffold no\n> longer carries its own connection-level reconnect — running it anyway goes permanently silent\n> after the first disconnect, **and that is indistinguishable from a quiet market**. The startup\n> check verifies the version and refuses to run. The required version is the frontmatter's\n> `requiredCliVersion`; `CLI_MIN` in the script matches it.\n\n### Check liveness with the right field\n\n`state[\"last_push_ms\"]` is the liveness signal — every push updates it, re-pushes included.\n\n**Do not use `last_event_ms`.** It is written after deduplication, so it only reflects whether a\n**new** `signalId` arrived. Half an hour of quiet on the signal stream is entirely normal, and\nusing that field for liveness turns a normal quiet spell into a false outage.\n\n### Profitable-exit bonus allowance (`state.bonus_slots`) — suggested, can be disabled\n\n> This is **an example of one position-management idea**, not a recommendation. It assumes \"a\n> profitable exit shows the strategy works in current conditions, so exposure can grow\" — an\n> assumption that holds in a trending market and amplifies drawdown in a choppy one. If you do not\n> want it, make `position_usd` an exact divisor of `budget_usd` and ignore the field.\n\nEvery exit that **settles at a profit** adds one `position_usd` slot of allowance:\n\n```\nposition ceiling = max_positions + bonus_slots\ncapital ceiling  = budget_usd    + bonus_slots × position_usd\n```\n\nLosing exits add nothing. **Nothing is added when proceeds cannot be determined\n(`proceeds is None`) either** — fail-closed: better to withhold allowance than to expand risk on a\nguess. Proceeds are read from the on-chain receive amount of the filling transaction.\n\n### Same-token cooldown (`policy.same_token_cooldown_h`) — suggested default 24, adjustable, can be disabled\n\nWithin the cooldown window, the same contract address is bought **only on the earliest signal**.\n\"Do I currently hold it?\" is not enough on its own — once a position closes, later signals for the\nsame token would pass again (a single token can produce several distinct `signalId`s in a day).\nThe cooldown origin is recorded in `state.json.ca_last[ca]`, independent of position state.\n\n## Configuration\n\n`$COPYTRADER_HOME\u002Fconfig.json` (default `~\u002F.local\u002Fcopytrader`). The first run generates an\n**entirely empty template**.\n\n> **Resource guardrails and strategy parameters have no defaults — a missing one refuses startup.**\n> Values like stop-loss distance and per-trade size have to be the result of your own decision,\n> not something copied. A stop-loss distance you never thought about is exactly as dangerous as a\n> position size you never thought about, so the scaffold would rather not start.\n> The one exception is `mode`: absent means `dry-run`, so an omission can never turn into live\n> trading.\n\n**Required (mechanism layer)**\n\n| Key | Meaning | How to decide it |\n|---|---|---|\n| `chain` | Chain ID | `baw wallet chains --json` for the currently supported set |\n| `quote_token` | Quote-token contract address | A stablecoin on that chain; **must be lowercase** |\n| `sources` | Trigger sources | `[\"address\"]` \u002F `[\"signal\"]` \u002F both |\n| `budget_usd` | Cumulative deployment cap | No reinvestment; monotonically increasing. Decide whether losing all of it is acceptable |\n| `position_usd` | Per-trade size | Together with stop-loss distance, this sets the worst case per trade |\n| `max_positions` | Concurrent position cap | Bounds total exposure together with `budget_usd` |\n| `gas_floor_native` | Native-token floor | Stops opening below this; **also stops if the balance cannot be read** |\n\n**Required (strategy parameters, read by the reference hooks)**\n\nThe `policy` section is passed to hooks verbatim and the mechanism layer does not interpret its\nkeys — replace the hooks and this table changes with them. The reference implementation requires:\n\n| Key | Meaning |\n|---|---|\n| `follow_sides` | Which `tradeSideCategory` values to follow on the address stream |\n| `max_event_age_sec` | Delivery freshness ceiling, in seconds |\n| `sl_mult` \u002F `tp_mult` | Stop-loss \u002F take-profit trigger = entry price × this |\n| `tp_fraction` | Fraction of the position sold at take-profit |\n| `buy_slippage` \u002F `sl_slippage` \u002F `tp_slippage` | Slippage tolerance per stage (%). **Stop-loss slippage should be wider than take-profit** — a stop that cannot fill during a crash is not protection |\n\n**Has defaults (plumbing that does not affect capital safety)**\n\n`mode` (`dry-run`) · `address_list` (`addrs.txt`) · `reconcile_sec` · `proc_restart_sec` ·\n`workers` · `outcome_horizons_min` (`[5, 15, 60]`; set to `[]` to switch outcome sampling off)\n\n**Optional**\n\n`policy.block_honeypot` (default `true`; disabling it is not advised) · `policy.require_audit` ·\n`policy.enrich_srcs` · `policy.same_token_cooldown_h` · `policy.min_liquidity_usd` ·\n`policy.block_risk_levels` · `policy.max_sell_tax_pct` · `policy.max_commit_ratio`\n\nRun `dry-run` for a while first and read the `decision` distribution in `events.jsonl` to confirm\nwhat each gate is actually rejecting, before deciding whether to go `live`.\n\n## Platform behavior notes\n\n### What `cli-check` actually returns\n\nIn `baw cli-check --required-version X --json`, `success` **only reports that the command ran, and\nis always `true`**. Whether the version passes is in `data.needUpdateCli`:\n\n```json\n{\"success\": true, \"data\": {\"currentCliVersion\": \"x.y.z\", \"needUpdateCli\": true}}\n```\n\nTreating `success` as \"version is fine\" makes the version gate useless: the command always\n\"succeeds\", so the gate always passes. The correct test is `data.needUpdateCli === false`.\n\n### Address casing is not consistent across chains\n\n**Lowercase every contract address you pass to the CLI.** Chains differ in how strictly they\nvalidate address format — some accept EIP-55 mixed case, others reject it outright:\n\n```\n[20003002] Invalid fromToken address\n```\n\nThe difference is not documented, and the error points at \"invalid address\" rather than \"wrong\nformat\", which reads as though the wrong token were configured.\n\n**The dangerous part is how it presents**: every order on that leg fails, and \"never filling\nanything\" looks exactly like \"this chain has no signals\" in every liveness metric. Unless failed\norders are counted explicitly, this can hide for a long time. That is why `state[\"buy_fails\"]`\nand the most recent error belong in whatever reporting you build.\n\n### Scoring decisions without spending money\n\n`events.jsonl` alone cannot tell you whether a decision was any good — it records the decision,\nnot the result. So every decision that *would* have opened a position (dry-run included, where\nnothing is bought) schedules price re-reads at `outcome_horizons_min` and appends them to\n`outcomes.jsonl`:\n\n```json\n{\"key\":\"sig:…\",\"ca\":\"0x…\",\"token\":\"…\",\"src\":\"signal\",\"horizon_min\":15,\n \"t0_ms\":…,\"entry\":0.0123,\"price\":0.0141,\"ret_pct\":14.63,\"sampled_ms\":…}\n```\n\nJoin on `key` to get one row per decision with its features and its forward return:\n\n```bash\npython3 - \u003C\u003C'EOF'\nimport json, collections\nev = {}\nfor l in open(\"events.jsonl\"):\n    r = json.loads(l)\n    if r.get(\"decision\") in (\"DRY_RUN\", \"OPENED\"): ev[r[\"key\"]] = r\nby = collections.defaultdict(dict)\nfor l in open(\"outcomes.jsonl\"):\n    o = json.loads(l)\n    if o[\"key\"] in ev and o.get(\"ret_pct\") is not None:\n        by[o[\"key\"]][o[\"horizon_min\"]] = o[\"ret_pct\"]\nprint(f\"{len(by)} scored decisions\")\nfor h in sorted({h for d in by.values() for h in d}):\n    v = sorted(d[h] for d in by.values() if h in d)\n    if v:\n        n = len(v)\n        print(f\"  {h:>3}min  n={n:\u003C4} median {v[n\u002F\u002F2]:+7.1f}%  \"\n              f\"win rate {sum(1 for x in v if x > 0)\u002Fn*100:.0f}%\")\nEOF\n```\n\nFrom there, split by whatever feature you are testing (`liquidity`, `top10`, `tax`, `smy`,\n`audit_risk`, token age from `launch_ms`, …) and compare the distributions.\n\n**Read these numbers for what they are:**\n\n- **They are marks, not fills.** No slippage, no fees, no token tax, no gas, and no check that the\n  position could actually have been exited at that price. Treat them as an *upper bound* on what\n  the strategy could have captured.\n- **A horizon is an instant, not a path.** A `+40%` at 60 min does not mean a stop-loss was never\n  touched on the way. Read several horizons together, and remember that a stop-loss between them\n  changes the real outcome entirely.\n- **Sample size still governs everything.** A handful of scored decisions tells you nothing, and\n  if the mean is carried by one or two outliers it tells you nothing either. Look at the median\n  and the distribution, not the average.\n- Samples read very late (after an outage, say) are marked `sampled_late` rather than being\n  quietly folded into the series.\n\n### Build your own baseline; do not use someone else's numbers\n\nThe quantities below shift with platform changes, chain, token type, and time of day, so **any\nhard-coded value goes stale**. The scaffold writes them all into `events.jsonl` \u002F\n`orders.jsonl` precisely so that you can measure your own baseline:\n\n| What to measure | How | The trap in the measurement itself |\n|---|---|---|\n| Delivery latency | `lag_s` = arrival time − event time | **On the signal stream, take the minimum lag per `signalId` and count only genuine first pushes** (test: `lag` in the seconds range). Treating every re-push as an independent observation turns \"the signal's current age\" into latency and can be orders of magnitude off |\n| Cause of latency | Use `conn_uptime_s` to separate \"the server was slow\" from \"we just reconnected and got a replay\" | Without that field there is no attribution, only a blended number |\n| Execution time | Per-step timings in `latency_ms` | If the reader thread makes blocking calls, processing time accumulates into the measured latency of later events |\n| Audit \u002F market coverage | Distribution of `hasResult` and `px_src` | Newly launched tokens are often unindexed in market data; coverage correlates strongly with token age, so pooling all ages together is meaningless |\n| Gas cost per trade | Native-balance delta across trades ÷ number of trades | Placing and cancelling limit orders also costs gas; counting only swaps understates the cost of a full position lifecycle |\n| Predictive power of token-quality features | Correlate `top10` \u002F `tags` \u002F `liquidity` \u002F `tax` \u002F `audit_risk` in `events.jsonl` against outcomes | **Sample size.** A single-digit number of fills teaches you nothing about expectancy; if returns concentrate in one or two trades, the mean is meaningless |\n\n> **Do not set token-quality thresholds by intuition.** Metrics like tax tags and top-10 holder\n> concentration are distributed very differently on newly launched tokens than intuition suggests\n> — a threshold set by feel rejects most legitimate candidates, and that over-rejection **looks\n> exactly like \"there are no signals\"**, which makes it hard to notice. Log first, test second,\n> gate last.\n\n## Pre-flight checks\n\n**Chain support, quote-token allowlists, and order quotas all change as the platform evolves — do\nnot rely on any hard-coded table.** Query current state before each start and let the results\ndefine what is available:\n\n```bash\nbaw wallet status --json                    # must be CONNECTED\nbaw wallet chains --json                    # which chains are supported right now\nbaw wallet settings --json                  # daily limit \u002F tradeAllTokens \u002F abnormalTxnHandling\nbaw wallet left-quota --json                # remaining quota today\nbaw wallet balance --binanceChainId \u003Cc> --json   # quote-token and native (gas) balances\n\n# Does the target chain support what you need? Probe with a quote — it prices a route without\n# placing anything on-chain.\nbaw market-order quote --fromTokenQty 1 --fromToken \u003Cquote> --toToken \u003Cany token> --binanceChainId \u003Cc> --json\nbaw limit-order list --binanceChainId \u003Cc> --json     # does the chain answer for limit orders at all\n```\n\n**Whether `limit-order` works decides whether you can place on-chain protective orders at all** —\non a chain without it, protection depends entirely on the process staying alive. Neither probe\nabove proves placement will succeed; the first real protective order does. Treat a chain as\nunverified until you have seen one reach `WORKING`, and start there with the smallest position\nsize you are willing to hold unprotected.\n\nError codes: `1001001` chain or operation unsupported · `1001002` invalid parameters · `100`\nserver error (on a chain that is not wired up this can also surface as \"no liquidity\", so\ndistinguish it from `1001001`).\n\nCommands and parameters for each dependency are authoritative in that skill's own docs and\n`--help`; this document does not duplicate their capability tables.\n\n## Running\n\n```bash\ncd \u003Cskill-dir>\u002Fscripts && python3 copytrader.py            # foreground\nnohup python3 -u copytrader.py >> runner.log 2>&1 & disown  # long-running\n```\n\n| Action | Command |\n|---|---|\n| Stop opening new positions | `touch ~\u002F.local\u002Fcopytrader\u002FSTOP` |\n| Exit the process | `touch ~\u002F.local\u002Fcopytrader\u002FKILL` |\n| Acknowledge the amount at risk (required before `mode: live` runs) | `echo \u003Cbudget_usd> > ~\u002F.local\u002Fcopytrader\u002FI_UNDERSTAND_THE_RISK` |\n| Restore the live gate | `rm ~\u002F.local\u002Fcopytrader\u002FI_UNDERSTAND_THE_RISK` |\n\nProcess exit **does not cancel protective orders already on-chain**; cancelling requires an\nexplicit `baw limit-order cancel`.\n\nData files (`~\u002F.local\u002Fcopytrader\u002F`):\n\n| File | Contents |\n|---|---|\n| `events.jsonl` | One line per event with the decision and all its inputs — **what the strategy decided** |\n| `outcomes.jsonl` | Price re-reads at each horizon for every decision that would have opened — **whether the decision was any good**. Join to `events.jsonl` on `key` |\n| `orders.jsonl` | Order \u002F limit-order \u002F cancel log |\n| `state.json` | Positions, deployed capital, handled keys |\n| `copytrader.log` | Chronological log |\n\nDiagnostic fields in `events.jsonl`: `lag_s` (delivery latency) · `conn_uptime_s` (how long the\nconnection had been stable on arrival — **use this to separate server-side delay from\npost-reconnect replay**) · `conn_seq` (which connection) · `replay` (event predates this\nconnection) · `latency_ms` (per-step timings) · `decision` (pass, or the rejection reason) ·\n`tax` `audit_risk` `liquidity` `top10` `px_src`.\n\n**The daemon has no external supervisor.** Configure your own liveness checks: is the process\nalive; is `state.json.last_push_ms` advancing (**not `last_event_ms`** — it is written after\ndeduplication and only reflects new `signalId`s, and half an hour of quiet on the signal stream is\nnormal); how fast is `conn_seq` growing; is `baw wallet status` still CONNECTED; does the active\norder count from `baw limit-order list` match the position count in `state.json`.\n\n## Known limitations\n\nThese are **inherent properties** of the scaffold, not a to-do list. Make sure you accept them\nbefore going live.\n\n| Limitation | Detail |\n|---|---|\n| **No strategy edge whatsoever** | The three bundled hooks are a minimal reference implementation for proving the pipeline runs. **They are not a recommended strategy and carry no evidence of expectancy.** The strategy is your work |\n| **Guardrails are not safety** | The scaffold runs the checks you configure; it does not judge whether they are sufficient. Set thresholds wide, or switch optional blocks off, and it will comply — **risk-control effectiveness depends on your values, not on this skill** |\n| **Structurally behind** | Your fill is necessarily later than the party you copy (push latency + decision + order). If they are an issuer or have a private execution path, their gains are not reproducible while their losses are copied in full |\n| **There is an unprotected window** | Time passes between the buy filling and the protective order being placed, bounded by settlement and API round-trips. The position has no downside protection in that window. It cannot be eliminated, only shortened |\n| **Quantities drift after a partial fill** | Once any protective order partially fills, the remaining orders no longer match the remaining position. The reconcile thread re-places against the actual balance, but a process exit inside the reconcile interval leaves over-sized orders behind |\n| **A stop-loss cannot save an illiquid token** | Being able to place an order is not the same as being able to fill it. A liquidity floor is the tool for that tail risk; a stop-loss is not |\n| **Dry-run is not equivalent to live** | Dry-run records no positions, so budget and concurrency guardrails never fire and the pass count is necessarily higher than live would open. Do not estimate live fill frequency from a dry-run pass rate |\n| **Process exit does not self-heal** | The scaffold restarts its child process when that exits; **the scaffold itself exiting has no external supervisor.** Configure process-level supervision yourself (launchd \u002F systemd \u002F container restart policy) |\n| **Latency measures \"platform record → delivery\"** | The relationship between the event timestamp and on-chain block time is undefined. If the event time already lags the chain, true end-to-end latency is larger than what you measure |\n| **Failed orders may consume daily quota** | Both consuming and not consuming have been observed. Not a constraint while the daily limit is generous, but do not assume failed orders are free when quota is tight |\n\n## Disclaimer\n\n**This is a scaffold, not a trading product, and it carries no strategy of its own.**\n\n- The bundled hooks are a minimal reference implementation provided to demonstrate that the\n  pipeline runs. They have **no evidence of positive expectancy** and are not a recommendation.\n- Every risk control, position-management scheme and parameter value in this skill is a\n  **suggestion**, not a safeguard. The scaffold runs the checks you configure; it does not judge\n  whether those checks are sufficient, and it will comply with thresholds set arbitrarily wide or\n  with optional protections switched off.\n- **Nothing here is investment, financial, or trading advice.** No representation is made that any\n  strategy assembled with this scaffold will be profitable or will avoid losses.\n- On-chain transactions are **irreversible**. Automated trading can lose money through market\n  conditions you did not anticipate, changes in platform or protocol behavior, defects in this\n  software, or defects in the strategy you write. Copy trading is additionally disadvantaged by\n  construction: your fill is always later than the party you copy, and if they are an issuer or\n  hold a private execution path, their gains are not reproducible while their losses are.\n- This software is provided **as-is, without warranty of any kind**, express or implied. To the\n  maximum extent permitted by law, no liability is accepted for any loss or damage arising from\n  its use.\n- **You are solely responsible** for what you run, for the parameters you choose, for complying\n  with the laws and regulations that apply to you, and for any funds you commit.\n\nIf you are not prepared to lose the full amount you configure as `budget_usd`, do not switch\n`mode` to `live`.\n","# Binance On-Chain Copy Trader\n\nA scaffold for a copy-trading pipeline. **This skill provides no strategy.** What it provides is:\na capability index, an event contract, an assembly structure, and three strategy hooks. The\nstrategy itself is yours to build and refine.\n\n> ## Read this first\n>\n> **Every risk control, position-management scheme, and parameter value in this skill is a\n> *suggestion* and an *example*. None of it is mandatory, and none of it constitutes a safety\n> guarantee or investment advice.**\n>\n> - The scaffold guarantees only that **it will run the checks you configure**. It does not\n>   guarantee those checks are sufficient to protect your funds. Budget caps, stop-loss distance,\n>   liquidity floors — you choose all of them. Set them wide, leave them out, or switch off the\n>   honeypot block, and the scaffold will do exactly as told.\n> - The three bundled hooks are a **minimal reference implementation that proves the pipeline\n>   runs**. They are not a recommended strategy and carry **no evidence of positive expectancy**.\n>   Running them live as-is means funding an unvalidated strategy with real money.\n> - On-chain transactions are irreversible. Any automated strategy can lose money through market\n>   conditions you did not anticipate, changes in platform behavior, or defects in this scaffold.\n>   **The risk is yours.**\n> - Suggested path: run `dry-run` long enough to matter → read `events.jsonl` and build your own\n>   baseline → switch to `live` with an amount you can afford to lose entirely → tune from there.\n\n## Dependencies\n\nConfirm the following skills are available in your current environment. This skill only\norchestrates; every underlying capability comes from them:\n\n| Skill | Provides | Used here |\n|---|---|---|\n| `binance-agentic-wallet` | Wallet, market orders, limit orders, quota, chain info | `wallet` `market-order` `limit-order` |\n| `binance-wallet-tracker` | Address monitoring, real-time push, group management | `tracker ws` `tracker token\u002Ftx` `tracker group\u002Faddress` |\n| ↳ | Must include the **Connection lifecycle** and **Signal field nullability** sections — this skill's connection-supervision split and its first-push field assumptions depend on them directly | — |\n| `binance-leaderboard` | Trader rankings, address scoring, holder lookup | `leaderboard query\u002Fanalyze\u002Falpha-radar` |\n| `binance-trading-signal` | Smart-money signals, custom strategies, backtests | `signal list` `signal strategy` `signal backtest` |\n| `query-token-audit` | Token security audit | Audit HTTP endpoint |\n| `query-token-info` | *(optional)* Live token price and market data | Only if a hook needs a live price when the event does not carry one |\n\nVerify:\n\n```bash\nbaw --version\nbaw cli-check --required-version \"$(grep -m1 requiredCliVersion SKILL.md | tr -dc '0-9.')\" --json\n#   ↑ the frontmatter `requiredCliVersion` is the single source of truth for the version floor.\n#     Below it, `tracker ws --duration 0` has no keepalive and no reconnect, and the scaffold\n#     refuses to start.\n```\n\nMissing any one of them disables the corresponding stage: without `binance-leaderboard` there is\nno systematic way to pick addresses; without `binance-trading-signal` you cannot create custom\nsignal strategies; without `query-token-audit` there is no audit data and `hard_gate` falls back\nto `require_audit` to decide whether to pass or reject.\n\nInstall source: `https:\u002F\u002Fgithub.com\u002Fbinance\u002Fbinance-skills-hub`\n\n## Getting started\n\nThe order that takes you from nothing to a scored dry-run. Each step points at the section below.\n\n**Note the ordering.** Writing the strategy comes *after* the first dry-run, not before. That is\ndeliberate: the whole premise of this scaffold is that thresholds should come from your own data,\nand before the first run you have none. So the first pass runs the bundled reference hooks\nunchanged — not because they are any good, but because they produce the dataset you need in order\nto write something better.\n\n**1 · Environment check** → see \"Pre-flight checks\"\nConfirm the wallet is CONNECTED, the target chain supports both `market-order` and `limit-order`,\nand that quote-token and gas balances are sufficient. On a chain where `limit-order` is\nunavailable you cannot place on-chain protective orders — accept that before continuing.\n\n**2 · Pick your trigger sources** → see \"Trigger sources\"\nAddress subscription, signal subscription, or both. This determines how you select sources next.\n\n**3 · Select sources**\n- Address source: `leaderboard query` for candidates → `leaderboard analyze` for the 6-dimension\n  score on each (`follow_friendly` is the most relevant dimension here) → write addresses into\n  `addrs.txt`, one per line, `#` for comments, **max 100**\n- Signal source: `signal explore` to browse official strategies \u002F `signal strategy create` to\n  build your own \u002F `signal strategy follow` to subscribe — or just use `--smy` and let the\n  platform's own judgement drive it, with no configuration at all\n\nThe sort dimension materially changes the character of the candidate pool\n(`--sort-by` 0=PnL 20=win rate 30=volume 50=trade count …), and individual dimensions can\nsaturate — over a short period, for instance, many addresses can tie at 100% win rate. Add your\nown secondary criteria to break ties.\n\n**4 · Write the config** → see \"Configuration\"\nThe first run writes an empty template to `$COPYTRADER_HOME` (default `~\u002F.local\u002Fcopytrader`) and\nrefuses to start until every required field is filled, listing exactly which are missing.\nMechanism parameters (budget \u002F per-trade size \u002F concurrency \u002F gas floor) are separate from\n`policy`, which is passed through to your hooks. **Leave `mode` as `dry-run`.**\n\nThe values here are decisions, not defaults to be guessed — `budget_usd` in particular should be\nan amount whose total loss is acceptable, because that is the number you will be asked to\nacknowledge at step 9.\n\n**5 · Dry-run with the bundled hooks unchanged**\n```bash\ncd \u003Cskill-dir>\u002Fscripts && python3 copytrader.py\n```\nDo not edit the hooks yet. What ships filters almost nothing (direction and freshness only), which\nmakes it a poor strategy but a good instrument: it lets through a broad sample so you can see what\nthe stream actually contains before you start rejecting things.\n\n**6 · Decide whether the plumbing works**\n```bash\ntail -f $COPYTRADER_HOME\u002Fcopytrader.log\n```\nCheck:\n- the startup log's `sources` and `policy` match what you intended\n- `events.jsonl` is being written, and the `decision` distribution is sane — are the rejection\n  reasons the ones you wanted?\n- passing events have values for `lag_s`, `tax`, `audit_risk`, `liquidity`, `price` — a missing\n  value means some upstream call returned nothing\n- `conn_seq` is not climbing fast (frequent reconnects mean an unstable stream)\n- `outcomes.jsonl` starts filling in once the first horizon elapses\n- `state.json`'s `deployed` stays at 0 under dry-run\n\nThis step is about the pipeline, not the strategy. Fix anything here before reading meaning into\nthe data.\n\n**7 · Now write your strategy** → see \"Strategy hooks\" and \"Scoring decisions without spending money\"\nWith a dataset in hand, edit the three functions in the `══`-delimited block at the top of\n`scripts\u002Fcopytrader.py`: `should_enter` \u002F `size_position` \u002F `exit_plan`.\n\nJoin `events.jsonl` and `outcomes.jsonl` on `key` and let that decide your thresholds. Every gate\nyou add should be one you can point at in the data — and you should be able to see, in the\n`decision` distribution, exactly what it rejected. Which parameters your hooks read is up to you;\nput them in the `policy` section of `config.json` and they arrive verbatim.\n\n**8 · Iterate**\nChange hooks → re-run → score again. **This all works in dry-run**, which is the point: outcome\nsampling does not need a fill, so a strategy can be evaluated from recorded data instead of from\nreal money. Accumulating a usable sample size is otherwise the expensive part.\n\nResist concluding early. A handful of scored decisions tells you nothing, and a mean carried by\none or two outliers tells you nothing either.\n\n**9 · Switch to live**\nSet `mode` to `live` **and** acknowledge the amount being risked — live mode refuses to start\nuntil the acknowledgement file contains the current `budget_usd`:\n\n```bash\necho \u003Cbudget_usd> > $COPYTRADER_HOME\u002FI_UNDERSTAND_THE_RISK\n```\n\n**The operator has to confirm the amount; an agent may write the file once they have.** What the\ngate is for is that the decision was made, and made about this specific number — not that a human\ntyped the command. So the natural flow is: the agent states the budget and what a full loss of it\nwould mean, the operator confirms, the agent writes the file and starts the run.\n\nWhy the amount rather than a bare `touch`: it cannot be inherited by copying someone else's\nruntime directory, the number has to come from whoever decided it, and **raising `budget_usd`\nlater invalidates the acknowledgement** — more money at risk deserves a fresh decision rather\nthan a stale one.\n\nBefore this point you should already have: run dry-run long enough to accumulate a meaningful\nsample, scored those decisions from `outcomes.jsonl` rather than from intuition, and concluded\nthat losing `budget_usd` in full is acceptable.\n\n**Dry-run does not record positions, so the budget and concurrency guardrails never fire — the\ndry-run pass count will therefore be higher than the number of positions live would actually\nopen.** Do not size live from a dry-run pass rate.\n\n## Capability map\n\nEvery stage of the pipeline maps to an existing capability. **The tables below are an index of\nwhere to look; treat each skill's own documentation and `--help` as authoritative for parameters.**\n\n### Source selection — pick addresses for the address source; pick or build strategies for the signal source\n\n| Capability | Command | Returns | Key parameters |\n|---|---|---|---|\n| Trader ranking | `baw leaderboard query` | address · winRate · realizedPnl · realizedPnlPercent · totalVolume · totalTxCnt · buyTxCnt · tags · addressLabel | `-c` chain · `-p` 7d\u002F30d\u002F90d · `-t` ALL\u002FKOL\u002FMPC · `--sort-by` 0=PnL 20=win rate 30=volume 50=trades 60=activity 70=rate 80=token count · `--page` · `--size` (≤20) |\n| Single-address score | `baw leaderboard analyze` | 6-dimension score (winrate \u002F stability \u002F drawdown \u002F tags \u002F pnl \u002F **follow_friendly**) plus an AI archetype | `-c` · `-a` address · `-p` · `--top-n` (≤5000) |\n| Reverse lookup by holding | `baw leaderboard alpha-radar` | Addresses holding a given token | `-c` · `-t` comma-separated token addresses · `-m` minimum hits · `-p` |\n| Token-level monitoring | `baw tracker token` | Recent token activity | `-c` · `-g` group · `--tag-type` kol\u002Fsmy · `--token-size` · `--period` 1m\u002F5m\u002F1h\u002F4h\u002F24h · `--filter-risk` |\n| Trade-level monitoring | `baw tracker tx` | Individual trades | same as above |\n| Followed addresses | `baw tracker follow` | The current follow list (read-only) | `-c` |\n| Group management | `baw tracker group` \u002F `address` | Create groups, bulk import, label, link | see wallet-tracker docs |\n\n### Trigger sources — two peer real-time subscriptions\n\nBoth go through `baw tracker ws` and both are WebSocket push with latency of the same order.\nThe difference is **who decides what is worth looking at**: with the address source you name the\nwallets; with the signal source the platform (or a strategy you built) decides. Run either alone\nor both together (`sources: [\"address\",\"signal\"]`).\n\n#### A · Address subscription — you pick the wallets, it pushes every trade they make\n\n| Command | Event semantics |\n|---|---|\n| `baw tracker ws --address-list \u003Cfile> -c \u003Cchain>` | Every on-chain trade by the listed addresses, **max 100 addresses** |\n| `baw tracker ws --address \u003Caddr> -c \u003Cchain>` | A single address |\n| `baw tracker ws --following -c \u003Cchain>` | The current follow list; requires login, mutually exclusive with the other flags |\n\n- **How to select**: `leaderboard query\u002Fanalyze\u002Falpha-radar`, plus `tracker group\u002Faddress` to build groups\n- **Event granularity**: one trade, one event; no re-pushes\n- **Direction**: `tradeSideCategory` — buys `{11,19}`, sells `{21,29}`\n- **Chains**: `-c` applies; single chain\n- **Entry price**: the event carries `tokenPrice` (the counterparty's actual fill price)\n- **Delivery latency**: measure it yourself. Expect a median on the order of seconds but a heavy\n  tail (P90 can reach minutes). Record real latency from the event timestamp rather than assuming.\n\n#### B · Signal subscription — the platform or your strategy decides, and pushes the verdict\n\n| Command | Event semantics |\n|---|---|\n| `baw tracker ws --smy` | Smart-money signals (multi-address consensus). **All chains; `-c` has no effect** |\n| `baw tracker ws --kol -c \u003Cchain>` | KOL-level events |\n| `baw tracker ws --wallet BSC,SOL,BASE,ETH` | Chain-level wallet activity, comma-separated |\n\n- **How to select**: `signal explore` to browse official strategies, `signal strategy create\u002Ffollow`\n  to build or subscribe to custom ones (meme-rush \u002F fomo-call), `signal backtest` to backtest\n- **Event granularity**: **the same `signalId` is pushed repeatedly with state updates** — on the\n  order of tens to hundreds of pushes per signal. Deciding \"this is a new signal\" requires\n  deduping by `signalId`\n- **Signal-only fields**: `smartMoneyCount` (how many smart-money addresses agree) · `exitRate`\n  (share already exited) · `maxGain` · `status`\n- **`status` semantics**: `valid`\u002F`active` live · `timeout` expired (one push at T+120min after\n  the trigger) · `outDecline` · `exitRate`\n- **Chains**: all-chain push; filter by `chainId` yourself\n- **Entry price**: `currentPrice` (often `null`) or `alertPrice` (the historical price at trigger\n  time — **not a currently tradable price**)\n- **Delivery latency**: measure it yourself, and mind the methodology — you **must take the\n  minimum lag per `signalId` and count only genuine first pushes**. Otherwise re-pushes turn \"the\n  signal's current age\" into \"latency\" and the result comes out orders of magnitude too high.\n\n#### Choosing between them\n\n| | Address source | Signal source |\n|---|---|---|\n| Who decides what to watch | You (address selection) | Platform verdict \u002F your custom strategy |\n| Meaning of one event | One person's single trade | Consensus across several addresses |\n| Coverage | Bounded by the 100-address cap | Platform-wide, all chains |\n| Dedupe required | No | **Yes** (by `signalId`) |\n| Timestamp field | `ts` | `signalTriggerTime` |\n| Event density | Depends on how active your chosen addresses are, and how many | Depends on platform verdicts and is unevenly distributed across chains — subscribing to one chain may mean long stretches with no events |\n\nShared parameter: `--duration \u003Csec>` (0 or omitted = unlimited). Each source occupies one reader\nthread in the scaffold; events are normalized by `norm_address()` \u002F `norm_signal()` and merged\ninto a single queue.\n\n### Signal query and strategy management (REST, not push)\n\n> The **real-time path for smart-money signals is `tracker ws --smy`** in the table above. This\n> group is REST query and strategy management — for backfill, filtering, building custom\n> strategies, and backtesting. It has nothing to do with latency.\n\n| Capability | Command | Key parameters |\n|---|---|---|\n| Signal feed (backfill) | `baw signal list` | `-c` chain · `-s` all\u002Fuser\u002Fmeme\u002Fsmart-money · `--time-range` 5m\u002F1h\u002F24h (filters on `signalTriggerTime`) · `--sort-by` time\u002FmaxGain · `-n` (≤100) |\n| Custom strategies | `baw signal strategy create\u002Fupdate\u002Fdelete\u002Ffollow\u002Funfollow\u002Flist\u002Flist-followed` | `-c` · `-t` meme-rush\u002Ffomo-call · `--job-id` · `--config` |\n| Backtests | `baw signal backtest list\u002Fdetail\u002Fretry\u002Fschedule` | `--interval` 4H\u002F6H\u002F12H\u002F24H\u002FOFF |\n| Backtest credits | `baw signal credits` | — |\n| Official strategy hall | `baw signal explore` | — |\n\n`signal list` returns fields from the same source as `tracker ws --smy` pushes (`signalId` values\nline up), but neither is a superset of the other.\n\n### Risk control and execution\n\n> The capabilities below are **available tools**. Whether and how you combine them is decided by\n> your hooks and your config. This skill does not mandate any particular check — it only\n> guarantees that the checks you asked for run at the right moment.\n\n| Capability | Command \u002F endpoint |\n|---|---|\n| Token audit | `POST https:\u002F\u002Fweb3.binance.com\u002Fbapi\u002Fdefi\u002Fv1\u002Fpublic\u002Fwallet-direct\u002Fsecurity\u002Ftoken\u002Faudit`, body `{binanceChainId, contractAddress, requestId}`. Returns `hasResult` `isSupported` `riskLevel` `extraInfo.buyTax\u002FsellTax` `riskItems[].details[].isHit` |\n| Market data | `GET ...\u002Fbuw\u002Fwallet\u002Fmarket\u002Ftoken\u002Fdynamic\u002Finfo\u002Fai?chainId=&contractAddress=` → `price` `liquidity` `holders` `volume24h` |\n| Quote | `baw market-order quote --fromTokenQty --fromToken --toToken --binanceChainId --slippage` |\n| Market order | `baw market-order swap` (same parameters plus `--mev` `--gasLevel`) → returns `orderId` |\n| Order lookup | `baw market-order list` → `status` `toTokenActualQty` `txHash` |\n| Limit order | `baw limit-order buy\u002Fsell --triggerPrice --fromTokenQty --fromToken --toToken --binanceChainId --slippage --mev --gasLevel` |\n| Cancel \u002F list | `baw limit-order cancel --strategyId` · `baw limit-order list` |\n| Guardrail readings | `baw wallet balance` · `left-quota` · `tx-lock` · `settings` · `chains` |\n\n## Event schema\n\nBoth sources are normalized by `norm_address()` \u002F `norm_signal()` into one structure. Hooks only\never see this:\n\n```python\n{\n  \"src\":   \"address\" | \"signal\",\n  \"key\":   dedupe key (address stream = txHash; signal stream = \"sig:\" + signalId),\n  \"ca\":    token contract address,\n  \"token\": token name,\n  \"price\": entry reference price (address stream = counterparty fill price `tokenPrice`;\n           signal stream = `currentPrice` or `alertPrice`),\n  \"ts\":    event time (epoch seconds) — time.time() - ts is the delivery latency,\n  \"chain\": chain ID,\n  \"side\":  11\u002F19 = buy, 21\u002F29 = sell (always 11 on the signal stream),\n  \"who\":   source identity (address stream = wallet label; signal stream = \"SMY×N\"),\n  \"usd\":   USD size of the counterparty's trade,\n  \"risk\":  tokenRiskLevel,\n  \"top10\": top-10 holder concentration,\n  \"tags\":  token tag array,\n  \"extra\": source-specific fields\n}\n```\n\n`extra` differs by source:\n\n| Source | `extra` contents |\n|---|---|\n| address | `addr` |\n| signal | `signalId` `status` `smy` (consensus count) `exitRate` `liq` `entry_liq` `holders` `is_alpha` `launch_ms` `mcap` `sig_seq` |\n\nFor the **full set of raw push fields** (including those dropped during normalization) see the\nfield tables in `binance-wallet-tracker`. Extend the `norm_*` functions to carry more of them\ninto `extra` when you need them.\n\n### Signal stream: field availability on first push vs re-push\n\n**Know this before you write any strategy.** `--smy` is a state stream, not an event stream — the\nsame `signalId` is pushed repeatedly throughout its lifetime, and **the first push and the\nre-pushes carry different fields**. A strategy can only use fields that are present on the first\npush, because the decision has to be made then.\n\nThe authoritative definition lives in the **Signal field nullability** section of\n`binance-wallet-tracker\u002Freferences\u002Fcli.md`. The table below is how that lands at the assembly\nlayer:\n\n| Field | First push | Usable for an entry decision? |\n|---|---|---|\n| `signalId` `ticker` `chainId` `contractAddress` | carried | Yes |\n| **`signalTriggerTime`** | **carried** | **Yes — compute delivery freshness from it** |\n| `alertPrice` `alertMarketCap` | carried | Yes (but note: historical price at trigger time, not a tradable price) |\n| `alertLiquidity` `entryLiquidity` | carried | Yes |\n| `top10` `holders` `smartMoneyCount` `isAlpha` `launchTime` | carried | Yes |\n| `status` | **usually `null`** | **No — see note 1** |\n| `exitRate` `maxGain` `currentPrice` | **usually `null`** | **No — see note 2** |\n\nNotes:\n\n1. **A `status` gate may only reject explicit bad values; a missing value must pass.** `status` is\n   usually `null` on the first push (the lifecycle states `timeout` \u002F `outDecline` \u002F `exitRate`\n   are stamped on later pushes). Writing `if st not in (\"valid\",\"active\")` silently drops almost\n   every genuine first push, **and the symptom is indistinguishable from \"there are no signals on\n   this chain\"**, which makes it very hard to diagnose. Correct form:\n\n   ```python\n   if st is not None and st not in (\"valid\", \"active\"):\n       return False, f\"status={st}\"\n   ```\n\n2. **Do not use `exitRate` \u002F `maxGain` \u002F `currentPrice` as entry conditions.** They describe how a\n   signal evolved *after* it fired; the server has not computed them at first-push time. A\n   threshold gate on them never fires on a first push and only misjudges older signals you joined\n   mid-life. Use them for exit logic or post-hoc correlation analysis instead — the fields are\n   still written to `events.jsonl` in full.\n\n3. **Do not place orders against `alertPrice` as if it were tradable.** It is the historical price\n   at trigger time; combined with delivery latency, using it as a fill price books an order that\n   cannot fill. This scaffold treats it purely as a **reference price handed to the hooks**, while\n   protective-order triggers are always derived from the real entry price computed as\n   `usd \u002F actual filled quantity`. Keep the two apart. If a hook needs a live price, query market\n   data (`query-token-info`) and skip when unavailable.\n\n4. **You do not need a market-data call for liquidity** — `alertLiquidity` is present on the first\n   push, and market data often has no index for newly launched tokens, making it less reliable\n   than the event's own field. Also note the signal source already filters on liquidity, so\n   **a liquidity floor on the signal stream is close to a no-op**; do not expect it to carry your\n   filtering.\n\n5. **Expired re-pushes must be caught by a freshness gate, not by `status`.** The `status=timeout`\n   expiry notice always arrives at T+120min after the trigger; it carries `status` but its\n   `signalTriggerTime` is old. The two gates back each other up: `status` catches explicit bad\n   values, freshness catches anything stale in time.\n\n## Assembly structure\n\n```\nws_reader(source)          one thread per source; timestamps and enqueues only, never blocks\n      ↓ queue\nworker × N\n      ↓\n  norm_* ─────────────► normalized event `ev`\n      ↓\n  should_enter(ev, ctx)    ← hook ①  ctx.audit \u002F liquidity are still None here\n      ↓ pass\n  gate_ok()                mechanism guardrails: budget \u002F positions \u002F gas \u002F tx-lock \u002F quota \u002F STOP\n      ↓\n  audit() ∥ token_market()  fetch audit and market data concurrently, completing ctx\n      ↓\n  hard_gate(ctx)            mechanism-forced check: audit has a result + honeypot (configurable)\n      ↓\n  should_enter(ev, ctx)    ← hook ① again, now with audit and liquidity\n      ↓ pass\n  size_position(ev, ctx)   ← hook ②  returns a USD amount\n      ↓\n  market-order swap → actual_qty() reads toTokenActualQty from market-order list\n      ↓\n  exit_plan(ev, ctx, entry, qty) ← hook ③  returns [(trigger_price, qty, slippage), ...]\n      ↓\n  place_protection()        places limit-order sells in the returned order\n      ↓\n  reconcile()               periodic: once any protective order fills, re-place against the\n                            actual remaining balance\n```\n\n### Why it is assembled this way\n\nThree non-obvious choices in the pipeline, each resting on an interface contract. Confirm the\ncontract still holds before changing them:\n\n| Choice | Contract it rests on |\n|---|---|\n| Filled quantity comes from `market-order list`, not from polling the wallet balance | `market-order swap` returns `orderId` and **neither a txHash nor a filled quantity**; the quantity is `toTokenActualQty` in `market-order list` |\n| `exit_plan` can express a stop-loss | `limit-order sell` accepts a `triggerPrice` **below market** and stays `status: WORKING` rather than filling immediately |\n| `ws_reader` **only restarts at the process level** | Connection-level care is built into `tracker ws --duration 0` (PING keepalive + auto-reconnect + backoff); the required CLI version is in the frontmatter's `requiredCliVersion`. The **Connection lifecycle** section of `binance-wallet-tracker` explicitly asks callers not to add a second layer — an outer rotation would kill a healthy connection, and an outer watchdog would abort a reconnect the CLI is already backing off for |\n\nTwo more choices affect how readings are interpreted: `ws_reader` records `conn_uptime_s` so\nserver-side delay can be told apart from post-reconnect replay; and the reader thread makes no\nblocking calls, because otherwise processing time accumulates and inflates the arrival timestamps\nof later events.\n\n## Strategy hooks\n\n> The three hooks are **where you write your strategy**. What ships in the repository is only an\n> example that makes the pipeline run — every judgement and every threshold in it should be\n> replaced by whatever your own analysis shows.\n\nThe three functions sit at the top of `scripts\u002Fcopytrader.py`; the mechanism layer never touches\nthem. Signatures:\n\n```python\nshould_enter(ev, ctx) -> (bool, reason)\nsize_position(ev, ctx) -> float            # USD; the mechanism layer then clamps to\n                                           # min(value, position_usd, remaining budget)\nexit_plan(ev, ctx, entry_price, qty) -> [(trigger_price, sell_qty, slippage_pct), ...]\n```\n\n`ctx` contents:\n\n| Key | Meaning |\n|---|---|\n| `audit` | Raw audit response (`None` on the first hook call) |\n| `liquidity` | Liquidity from market data (`None` on the first call; the signal stream can fall back to `extra.liq`) |\n| `price` | Entry reference price |\n| `positions` | Current positions dict |\n| `deployed` | USD deployed so far |\n| `cfg` | Full config |\n| `policy` | The `policy` section of `config.json`, **passed through verbatim; the mechanism layer does not interpret its keys** |\n\n`should_enter` is called **twice**: once **before spending anything on audit and market data**\n(only the event's own fields are available), and once **after both are ready**. Put cheap\njudgements in the first call and anything that needs audit data in the second.\n\nHelper: `audit_tax(a)` pulls `buyTax + sellTax` out of an audit response.\n\n## Mechanism guardrails\n\n**Two different things.** *Running* a guardrail is the mechanism layer's job and hooks cannot get\naround it; the *values and switches* are your decision.\n\n| | Who decides | Note |\n|---|---|---|\n| When a check runs and who runs it | The scaffold | e.g. \"check the budget before every entry\" cannot be switched off |\n| **What threshold a check uses, and whether it is enabled** | **You** | How large `budget_usd` is, whether `block_honeypot` stays on — the scaffold executes whatever the config says |\n| What to buy, how much, and how to exit once a check passes | **Your hooks** | The mechanism layer only clamps ceilings; it does not pick instruments |\n\nSo what follows is a **suggested set of guardrails, not a safety guarantee**. A config with\n`budget_usd: 1000000` and the honeypot block switched off will run perfectly happily.\n\n### The guardrail list\n\n| Item | Behavior |\n|---|---|\n| Budget | Cumulative deployment never exceeds `budget_usd`; `size_position`'s return value is clamped |\n| Per trade | Never exceeds `position_usd` |\n| Concurrency | Never exceeds `max_positions` |\n| Gas | Stops opening when the native balance is below `gas_floor_native`; **also stops if the balance cannot be read** |\n| Serialization | No orders while `tx-lock` reports LOCKED |\n| Quota | No orders when `left-quota` is insufficient |\n| Same token | A token already held is not opened again |\n| Single instance | pidfile lock; a second start exits immediately |\n| Gates | `STOP` halts new entries (existing protective orders are untouched); `KILL` exits the process |\n| Mode | Under `mode: dry-run` no order request is issued at all |\n| Live acknowledgement | `mode: live` refuses to start unless `$COPYTRADER_HOME\u002FI_UNDERSTAND_THE_RISK` contains the current `budget_usd`. Cannot be inherited by copying a runtime directory, and raising the budget invalidates it |\n\n**Switching `mode` from `dry-run` to `live` requires the operator's explicit decision about a\nspecific amount**, and the scaffold enforces that with the acknowledgement file above rather than\ntrusting a config edit alone. An agent may write the file after the operator confirms the amount.\n\n### The connection-supervision split\n\n**Connection-level care belongs to the CLI; process-level care belongs to this scaffold.** Do not\ndo both.\n\n| Layer | Owner | What it does |\n|---|---|---|\n| Connection | **CLI** | `tracker ws --duration 0` has it built in: a 30s application-level PING, auto-reconnect and re-SUBSCRIBE on `onclose`, exponential backoff (reset on any received push) |\n| Process | **This scaffold** | Restarts the child process only when it actually exits (fixed short delay, `proc_restart_sec`), and writes a `state[\"stream_alarm\"]` |\n\nWhy they must not be stacked (the **Connection lifecycle** section of `binance-wallet-tracker`\nstates this explicitly):\n\n- an outer \"active rotation\" periodically kills a connection the CLI was maintaining perfectly well\n- an outer \"silence watchdog\" force-kills the child while the CLI is mid-backoff, aborting a pending reconnect\n- two nested backoffs make the real reconnect interval unpredictable\n\n`--duration N > 0` is **different semantics**: a single connection that rejects on disconnect and\ndoes not reconnect. Use it for one-off sampling, never for a long-running process.\n\n> **The version floor is hard.** Built-in keepalive is a precondition of this scaffold. Below the\n> required CLI version, `--duration 0` has neither keepalive nor reconnect, and the scaffold no\n> longer carries its own connection-level reconnect — running it anyway goes permanently silent\n> after the first disconnect, **and that is indistinguishable from a quiet market**. The startup\n> check verifies the version and refuses to run. The required version is the frontmatter's\n> `requiredCliVersion`; `CLI_MIN` in the script matches it.\n\n### Check liveness with the right field\n\n`state[\"last_push_ms\"]` is the liveness signal — every push updates it, re-pushes included.\n\n**Do not use `last_event_ms`.** It is written after deduplication, so it only reflects whether a\n**new** `signalId` arrived. Half an hour of quiet on the signal stream is entirely normal, and\nusing that field for liveness turns a normal quiet spell into a false outage.\n\n### Profitable-exit bonus allowance (`state.bonus_slots`) — suggested, can be disabled\n\n> This is **an example of one position-management idea**, not a recommendation. It assumes \"a\n> profitable exit shows the strategy works in current conditions, so exposure can grow\" — an\n> assumption that holds in a trending market and amplifies drawdown in a choppy one. If you do not\n> want it, make `position_usd` an exact divisor of `budget_usd` and ignore the field.\n\nEvery exit that **settles at a profit** adds one `position_usd` slot of allowance:\n\n```\nposition ceiling = max_positions + bonus_slots\ncapital ceiling  = budget_usd    + bonus_slots × position_usd\n```\n\nLosing exits add nothing. **Nothing is added when proceeds cannot be determined\n(`proceeds is None`) either** — fail-closed: better to withhold allowance than to expand risk on a\nguess. Proceeds are read from the on-chain receive amount of the filling transaction.\n\n### Same-token cooldown (`policy.same_token_cooldown_h`) — suggested default 24, adjustable, can be disabled\n\nWithin the cooldown window, the same contract address is bought **only on the earliest signal**.\n\"Do I currently hold it?\" is not enough on its own — once a position closes, later signals for the\nsame token would pass again (a single token can produce several distinct `signalId`s in a day).\nThe cooldown origin is recorded in `state.json.ca_last[ca]`, independent of position state.\n\n## Configuration\n\n`$COPYTRADER_HOME\u002Fconfig.json` (default `~\u002F.local\u002Fcopytrader`). The first run generates an\n**entirely empty template**.\n\n> **Resource guardrails and strategy parameters have no defaults — a missing one refuses startup.**\n> Values like stop-loss distance and per-trade size have to be the result of your own decision,\n> not something copied. A stop-loss distance you never thought about is exactly as dangerous as a\n> position size you never thought about, so the scaffold would rather not start.\n> The one exception is `mode`: absent means `dry-run`, so an omission can never turn into live\n> trading.\n\n**Required (mechanism layer)**\n\n| Key | Meaning | How to decide it |\n|---|---|---|\n| `chain` | Chain ID | `baw wallet chains --json` for the currently supported set |\n| `quote_token` | Quote-token contract address | A stablecoin on that chain; **must be lowercase** |\n| `sources` | Trigger sources | `[\"address\"]` \u002F `[\"signal\"]` \u002F both |\n| `budget_usd` | Cumulative deployment cap | No reinvestment; monotonically increasing. Decide whether losing all of it is acceptable |\n| `position_usd` | Per-trade size | Together with stop-loss distance, this sets the worst case per trade |\n| `max_positions` | Concurrent position cap | Bounds total exposure together with `budget_usd` |\n| `gas_floor_native` | Native-token floor | Stops opening below this; **also stops if the balance cannot be read** |\n\n**Required (strategy parameters, read by the reference hooks)**\n\nThe `policy` section is passed to hooks verbatim and the mechanism layer does not interpret its\nkeys — replace the hooks and this table changes with them. The reference implementation requires:\n\n| Key | Meaning |\n|---|---|\n| `follow_sides` | Which `tradeSideCategory` values to follow on the address stream |\n| `max_event_age_sec` | Delivery freshness ceiling, in seconds |\n| `sl_mult` \u002F `tp_mult` | Stop-loss \u002F take-profit trigger = entry price × this |\n| `tp_fraction` | Fraction of the position sold at take-profit |\n| `buy_slippage` \u002F `sl_slippage` \u002F `tp_slippage` | Slippage tolerance per stage (%). **Stop-loss slippage should be wider than take-profit** — a stop that cannot fill during a crash is not protection |\n\n**Has defaults (plumbing that does not affect capital safety)**\n\n`mode` (`dry-run`) · `address_list` (`addrs.txt`) · `reconcile_sec` · `proc_restart_sec` ·\n`workers` · `outcome_horizons_min` (`[5, 15, 60]`; set to `[]` to switch outcome sampling off)\n\n**Optional**\n\n`policy.block_honeypot` (default `true`; disabling it is not advised) · `policy.require_audit` ·\n`policy.enrich_srcs` · `policy.same_token_cooldown_h` · `policy.min_liquidity_usd` ·\n`policy.block_risk_levels` · `policy.max_sell_tax_pct` · `policy.max_commit_ratio`\n\nRun `dry-run` for a while first and read the `decision` distribution in `events.jsonl` to confirm\nwhat each gate is actually rejecting, before deciding whether to go `live`.\n\n## Platform behavior notes\n\n### What `cli-check` actually returns\n\nIn `baw cli-check --required-version X --json`, `success` **only reports that the command ran, and\nis always `true`**. Whether the version passes is in `data.needUpdateCli`:\n\n```json\n{\"success\": true, \"data\": {\"currentCliVersion\": \"x.y.z\", \"needUpdateCli\": true}}\n```\n\nTreating `success` as \"version is fine\" makes the version gate useless: the command always\n\"succeeds\", so the gate always passes. The correct test is `data.needUpdateCli === false`.\n\n### Address casing is not consistent across chains\n\n**Lowercase every contract address you pass to the CLI.** Chains differ in how strictly they\nvalidate address format — some accept EIP-55 mixed case, others reject it outright:\n\n```\n[20003002] Invalid fromToken address\n```\n\nThe difference is not documented, and the error points at \"invalid address\" rather than \"wrong\nformat\", which reads as though the wrong token were configured.\n\n**The dangerous part is how it presents**: every order on that leg fails, and \"never filling\nanything\" looks exactly like \"this chain has no signals\" in every liveness metric. Unless failed\norders are counted explicitly, this can hide for a long time. That is why `state[\"buy_fails\"]`\nand the most recent error belong in whatever reporting you build.\n\n### Scoring decisions without spending money\n\n`events.jsonl` alone cannot tell you whether a decision was any good — it records the decision,\nnot the result. So every decision that *would* have opened a position (dry-run included, where\nnothing is bought) schedules price re-reads at `outcome_horizons_min` and appends them to\n`outcomes.jsonl`:\n\n```json\n{\"key\":\"sig:…\",\"ca\":\"0x…\",\"token\":\"…\",\"src\":\"signal\",\"horizon_min\":15,\n \"t0_ms\":…,\"entry\":0.0123,\"price\":0.0141,\"ret_pct\":14.63,\"sampled_ms\":…}\n```\n\nJoin on `key` to get one row per decision with its features and its forward return:\n\n```bash\npython3 - \u003C\u003C'EOF'\nimport json, collections\nev = {}\nfor l in open(\"events.jsonl\"):\n    r = json.loads(l)\n    if r.get(\"decision\") in (\"DRY_RUN\", \"OPENED\"): ev[r[\"key\"]] = r\nby = collections.defaultdict(dict)\nfor l in open(\"outcomes.jsonl\"):\n    o = json.loads(l)\n    if o[\"key\"] in ev and o.get(\"ret_pct\") is not None:\n        by[o[\"key\"]][o[\"horizon_min\"]] = o[\"ret_pct\"]\nprint(f\"{len(by)} scored decisions\")\nfor h in sorted({h for d in by.values() for h in d}):\n    v = sorted(d[h] for d in by.values() if h in d)\n    if v:\n        n = len(v)\n        print(f\"  {h:>3}min  n={n:\u003C4} median {v[n\u002F\u002F2]:+7.1f}%  \"\n              f\"win rate {sum(1 for x in v if x > 0)\u002Fn*100:.0f}%\")\nEOF\n```\n\nFrom there, split by whatever feature you are testing (`liquidity`, `top10`, `tax`, `smy`,\n`audit_risk`, token age from `launch_ms`, …) and compare the distributions.\n\n**Read these numbers for what they are:**\n\n- **They are marks, not fills.** No slippage, no fees, no token tax, no gas, and no check that the\n  position could actually have been exited at that price. Treat them as an *upper bound* on what\n  the strategy could have captured.\n- **A horizon is an instant, not a path.** A `+40%` at 60 min does not mean a stop-loss was never\n  touched on the way. Read several horizons together, and remember that a stop-loss between them\n  changes the real outcome entirely.\n- **Sample size still governs everything.** A handful of scored decisions tells you nothing, and\n  if the mean is carried by one or two outliers it tells you nothing either. Look at the median\n  and the distribution, not the average.\n- Samples read very late (after an outage, say) are marked `sampled_late` rather than being\n  quietly folded into the series.\n\n### Build your own baseline; do not use someone else's numbers\n\nThe quantities below shift with platform changes, chain, token type, and time of day, so **any\nhard-coded value goes stale**. The scaffold writes them all into `events.jsonl` \u002F\n`orders.jsonl` precisely so that you can measure your own baseline:\n\n| What to measure | How | The trap in the measurement itself |\n|---|---|---|\n| Delivery latency | `lag_s` = arrival time − event time | **On the signal stream, take the minimum lag per `signalId` and count only genuine first pushes** (test: `lag` in the seconds range). Treating every re-push as an independent observation turns \"the signal's current age\" into latency and can be orders of magnitude off |\n| Cause of latency | Use `conn_uptime_s` to separate \"the server was slow\" from \"we just reconnected and got a replay\" | Without that field there is no attribution, only a blended number |\n| Execution time | Per-step timings in `latency_ms` | If the reader thread makes blocking calls, processing time accumulates into the measured latency of later events |\n| Audit \u002F market coverage | Distribution of `hasResult` and `px_src` | Newly launched tokens are often unindexed in market data; coverage correlates strongly with token age, so pooling all ages together is meaningless |\n| Gas cost per trade | Native-balance delta across trades ÷ number of trades | Placing and cancelling limit orders also costs gas; counting only swaps understates the cost of a full position lifecycle |\n| Predictive power of token-quality features | Correlate `top10` \u002F `tags` \u002F `liquidity` \u002F `tax` \u002F `audit_risk` in `events.jsonl` against outcomes | **Sample size.** A single-digit number of fills teaches you nothing about expectancy; if returns concentrate in one or two trades, the mean is meaningless |\n\n> **Do not set token-quality thresholds by intuition.** Metrics like tax tags and top-10 holder\n> concentration are distributed very differently on newly launched tokens than intuition suggests\n> — a threshold set by feel rejects most legitimate candidates, and that over-rejection **looks\n> exactly like \"there are no signals\"**, which makes it hard to notice. Log first, test second,\n> gate last.\n\n## Pre-flight checks\n\n**Chain support, quote-token allowlists, and order quotas all change as the platform evolves — do\nnot rely on any hard-coded table.** Query current state before each start and let the results\ndefine what is available:\n\n```bash\nbaw wallet status --json                    # must be CONNECTED\nbaw wallet chains --json                    # which chains are supported right now\nbaw wallet settings --json                  # daily limit \u002F tradeAllTokens \u002F abnormalTxnHandling\nbaw wallet left-quota --json                # remaining quota today\nbaw wallet balance --binanceChainId \u003Cc> --json   # quote-token and native (gas) balances\n\n# Does the target chain support what you need? Probe with a quote — it prices a route without\n# placing anything on-chain.\nbaw market-order quote --fromTokenQty 1 --fromToken \u003Cquote> --toToken \u003Cany token> --binanceChainId \u003Cc> --json\nbaw limit-order list --binanceChainId \u003Cc> --json     # does the chain answer for limit orders at all\n```\n\n**Whether `limit-order` works decides whether you can place on-chain protective orders at all** —\non a chain without it, protection depends entirely on the process staying alive. Neither probe\nabove proves placement will succeed; the first real protective order does. Treat a chain as\nunverified until you have seen one reach `WORKING`, and start there with the smallest position\nsize you are willing to hold unprotected.\n\nError codes: `1001001` chain or operation unsupported · `1001002` invalid parameters · `100`\nserver error (on a chain that is not wired up this can also surface as \"no liquidity\", so\ndistinguish it from `1001001`).\n\nCommands and parameters for each dependency are authoritative in that skill's own docs and\n`--help`; this document does not duplicate their capability tables.\n\n## Running\n\n```bash\ncd \u003Cskill-dir>\u002Fscripts && python3 copytrader.py            # foreground\nnohup python3 -u copytrader.py >> runner.log 2>&1 & disown  # long-running\n```\n\n| Action | Command |\n|---|---|\n| Stop opening new positions | `touch ~\u002F.local\u002Fcopytrader\u002FSTOP` |\n| Exit the process | `touch ~\u002F.local\u002Fcopytrader\u002FKILL` |\n| Acknowledge the amount at risk (required before `mode: live` runs) | `echo \u003Cbudget_usd> > ~\u002F.local\u002Fcopytrader\u002FI_UNDERSTAND_THE_RISK` |\n| Restore the live gate | `rm ~\u002F.local\u002Fcopytrader\u002FI_UNDERSTAND_THE_RISK` |\n\nProcess exit **does not cancel protective orders already on-chain**; cancelling requires an\nexplicit `baw limit-order cancel`.\n\nData files (`~\u002F.local\u002Fcopytrader\u002F`):\n\n| File | Contents |\n|---|---|\n| `events.jsonl` | One line per event with the decision and all its inputs — **what the strategy decided** |\n| `outcomes.jsonl` | Price re-reads at each horizon for every decision that would have opened — **whether the decision was any good**. Join to `events.jsonl` on `key` |\n| `orders.jsonl` | Order \u002F limit-order \u002F cancel log |\n| `state.json` | Positions, deployed capital, handled keys |\n| `copytrader.log` | Chronological log |\n\nDiagnostic fields in `events.jsonl`: `lag_s` (delivery latency) · `conn_uptime_s` (how long the\nconnection had been stable on arrival — **use this to separate server-side delay from\npost-reconnect replay**) · `conn_seq` (which connection) · `replay` (event predates this\nconnection) · `latency_ms` (per-step timings) · `decision` (pass, or the rejection reason) ·\n`tax` `audit_risk` `liquidity` `top10` `px_src`.\n\n**The daemon has no external supervisor.** Configure your own liveness checks: is the process\nalive; is `state.json.last_push_ms` advancing (**not `last_event_ms`** — it is written after\ndeduplication and only reflects new `signalId`s, and half an hour of quiet on the signal stream is\nnormal); how fast is `conn_seq` growing; is `baw wallet status` still CONNECTED; does the active\norder count from `baw limit-order list` match the position count in `state.json`.\n\n## Known limitations\n\nThese are **inherent properties** of the scaffold, not a to-do list. Make sure you accept them\nbefore going live.\n\n| Limitation | Detail |\n|---|---|\n| **No strategy edge whatsoever** | The three bundled hooks are a minimal reference implementation for proving the pipeline runs. **They are not a recommended strategy and carry no evidence of expectancy.** The strategy is your work |\n| **Guardrails are not safety** | The scaffold runs the checks you configure; it does not judge whether they are sufficient. Set thresholds wide, or switch optional blocks off, and it will comply — **risk-control effectiveness depends on your values, not on this skill** |\n| **Structurally behind** | Your fill is necessarily later than the party you copy (push latency + decision + order). If they are an issuer or have a private execution path, their gains are not reproducible while their losses are copied in full |\n| **There is an unprotected window** | Time passes between the buy filling and the protective order being placed, bounded by settlement and API round-trips. The position has no downside protection in that window. It cannot be eliminated, only shortened |\n| **Quantities drift after a partial fill** | Once any protective order partially fills, the remaining orders no longer match the remaining position. The reconcile thread re-places against the actual balance, but a process exit inside the reconcile interval leaves over-sized orders behind |\n| **A stop-loss cannot save an illiquid token** | Being able to place an order is not the same as being able to fill it. A liquidity floor is the tool for that tail risk; a stop-loss is not |\n| **Dry-run is not equivalent to live** | Dry-run records no positions, so budget and concurrency guardrails never fire and the pass count is necessarily higher than live would open. Do not estimate live fill frequency from a dry-run pass rate |\n| **Process exit does not self-heal** | The scaffold restarts its child process when that exits; **the scaffold itself exiting has no external supervisor.** Configure process-level supervision yourself (launchd \u002F systemd \u002F container restart policy) |\n| **Latency measures \"platform record → delivery\"** | The relationship between the event timestamp and on-chain block time is undefined. If the event time already lags the chain, true end-to-end latency is larger than what you measure |\n| **Failed orders may consume daily quota** | Both consuming and not consuming have been observed. Not a constraint while the daily limit is generous, but do not assume failed orders are free when quota is tight |\n\n## Disclaimer\n\n**This is a scaffold, not a trading product, and it carries no strategy of its own.**\n\n- The bundled hooks are a minimal reference implementation provided to demonstrate that the\n  pipeline runs. They have **no evidence of positive expectancy** and are not a recommendation.\n- Every risk control, position-management scheme and parameter value in this skill is a\n  **suggestion**, not a safeguard. The scaffold runs the checks you configure; it does not judge\n  whether those checks are sufficient, and it will comply with thresholds set arbitrarily wide or\n  with optional protections switched off.\n- **Nothing here is investment, financial, or trading advice.** No representation is made that any\n  strategy assembled with this scaffold will be profitable or will avoid losses.\n- On-chain transactions are **irreversible**. Automated trading can lose money through market\n  conditions you did not anticipate, changes in platform or protocol behavior, defects in this\n  software, or defects in the strategy you write. Copy trading is additionally disadvantaged by\n  construction: your fill is always later than the party you copy, and if they are an issuer or\n  hold a private execution path, their gains are not reproducible while their losses are.\n- This software is provided **as-is, without warranty of any kind**, express or implied. To the\n  maximum extent permitted by law, no liability is accepted for any loss or damage arising from\n  its use.\n- **You are solely responsible** for what you run, for the parameters you choose, for complying\n  with the laws and regulations that apply to you, and for any funds you commit.\n\nIf you are not prepared to lose the full amount you configure as `budget_usd`, do not switch\n`mode` to `live`.\n",{"name":5,"metadata":46,"description":56},{"version":47,"requires":48,"requiredCliVersion":55},"0.6.0",{"skills":49},[50,51,52,53,54],"binance-agentic-wallet","binance-wallet-tracker","binance-leaderboard","binance-trading-signal","query-token-audit","1.9.1","Scaffold for assembling on-chain copy-trading strategies on Binance Agentic Wallet. Wires the\nexisting capabilities — address monitoring, signal subscription, address scoring, token audit,\norder placement, on-chain take-profit\u002Fstop-loss — into one runnable pipeline, and exposes every\nstrategy decision as a hook. Ships no strategy of its own.\nTrigger on: copy trade, copy trading, follow smart money, follow a wallet, mirror trades,\ncopy-trade bot, auto-buy on signal, monitor a wallet and trade, smart money copy trading,\nsignal-driven trading, pick addresses to copy, copy-trade strategy, copy-trade status,\ncopy-trade post-mortem.\nNOT for: single manual trades (use binance-agentic-wallet), signal queries alone\n(binance-trading-signal), address analysis alone (binance-wallet-tracker \u002F binance-leaderboard).\n","main","3df1d0d67b30ff15236561f8c0f9f06d33f42dfd","skills\u002Fexchanges\u002Fbinance-official-binance-onchain-copy-trader",17,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia","https:\u002F\u002Feth2030.com","Hardcore infra. Building @alt-research and applied cryptography.","2026-11-13 02:31:19",{"source":8,"skillName":5,"commands":67,"prompt":77,"zipAvailable":78},[68,71,74],{"tool":69,"command":70},"npx","npx skills add jiayaoqijia\u002Fcryptoskill --skill binance-onchain-copy-trader",{"tool":72,"command":73},"bunx","bunx skills add jiayaoqijia\u002Fcryptoskill --skill binance-onchain-copy-trader",{"tool":75,"command":76},"pnpm","pnpm dlx skills add jiayaoqijia\u002Fcryptoskill --skill binance-onchain-copy-trader","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fbinance-official-binance-onchain-copy-trader\u002FSKILL.md",true,[80,86,92],{"path":81,"resourceType":82,"resourceTypeDesc":83,"sizeBytes":84,"sourceHtmlUrl":85},"scripts\u002Fcopytrader.py","SCRIPT","脚本",68383,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fbinance-official-binance-onchain-copy-trader\u002Fscripts\u002Fcopytrader.py",{"path":87,"resourceType":88,"resourceTypeDesc":89,"sizeBytes":90,"sourceHtmlUrl":91},"SOURCE.md","REFERENCE","参考文档",378,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fbinance-official-binance-onchain-copy-trader\u002FSOURCE.md",{"path":93,"resourceType":88,"resourceTypeDesc":89,"sizeBytes":94,"sourceHtmlUrl":95},"TRUST.auto.yaml",2232,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fbinance-official-binance-onchain-copy-trader\u002FTRUST.auto.yaml",[97,126,149,166,179,189],{"skillNo":98,"name":99,"nameZh":6,"description":100,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":101,"licenseFileUrl":102,"sourceHtmlUrl":103,"categories":104,"keywords":105,"publishedAt":41},"01M712C436EQYE43342Q4E7GG1","recipe-performance","Diagnose a specific MetaMask user flow's real-app performance and Sentry critical-user-flow telemetry with deterministic mm-harness recipes. Use for CUF boundaries, cold\u002Fwarm\u002Fbackground-resume behavior, latency regressions, lifecycle tags, duplicate or blocking network requests, long tasks, layout\u002Fpaint cost, screen redraws, React rerenders, or browser trace analysis where tests alone cannot prove the real app.","MIT","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fwallets\u002Fmetamask-official-recipe-performance\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fwallets\u002Fmetamask-official-recipe-performance\u002FSKILL.md",[],[106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125],"performance","recipe performance","recipe","mm","sentry","harness","app","deterministic","recipes","flow","cold","critical","analysis","tasks","react","browser","layout","screen","network","metamask",{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":130,"licenseFileUrl":131,"sourceHtmlUrl":132,"categories":133,"keywords":134,"publishedAt":41},"01M70XT2F8A5CQZ81JBP98KSW3","mexc-spot-websocket","MEXC Spot WebSocket workflows for public streams, protobuf handling, depth maintenance, listen keys, and private streams without exposing API keys.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-websocket\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-websocket\u002FSKILL.md",[],[135,136,137,138,139,140,141,142,143,144,145,146,147,148],"mexc spot websocket","spot","websocket","api","workflows","public","listen","streams","depth","keys","for","api keys","maintenance","protobuf",{"skillNo":150,"name":151,"nameZh":6,"description":152,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":130,"licenseFileUrl":153,"sourceHtmlUrl":154,"categories":155,"keywords":156,"publishedAt":41},"01M70XT0MBXN3WZY1BKN0CPNKR","mexc-spot-rest","MEXC Spot REST workflows for public data, signed account requests, orders, wallet\u002Fadmin actions, and secure signing without exposing API keys.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-rest\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-rest\u002FSKILL.md",[],[157,136,158,159,160,34,161,146,145,144,162,163,164,140,165,139,138],"mexc spot rest","REST","admin","signing","requests","actions","secure","data","orders",{"skillNo":167,"name":168,"nameZh":6,"description":169,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":130,"licenseFileUrl":170,"sourceHtmlUrl":171,"categories":172,"keywords":173,"publishedAt":41},"01M70XSYSVZ2N0N91XCAR2CAK0","mexc-futures-websocket","MEXC Futures WebSocket workflows for public streams, private account\u002Forder\u002Fposition streams, ping\u002Fpong, subscriptions, and depth maintenance.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-futures-websocket\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-futures-websocket\u002FSKILL.md",[],[174,175,137,176,177,147,145,178,143,142,140,139],"mexc futures websocket","futures","position","ping","subscriptions",{"skillNo":180,"name":181,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":101,"licenseFileUrl":182,"sourceHtmlUrl":183,"categories":184,"keywords":185,"publishedAt":41},"01M6H0ZWHVE5W04WG2DKQE2SQC","0xklen-version-and-refresh-sanctions-lists","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-version-and-refresh-sanctions-lists\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-version-and-refresh-sanctions-lists\u002FSKILL.md",[],[186,187,188],"refresh","0xklen version and refresh sanctions lists","version",{"skillNo":190,"name":191,"nameZh":6,"description":192,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":101,"licenseFileUrl":193,"sourceHtmlUrl":194,"categories":195,"keywords":196,"publishedAt":41},"01M6H0Z28Q3R8J0S799GJQWXM3","verify-tests-cover-changed-lines","Use when a PR adds code that the existing suite may not exercise. Measures patch coverage — the share of newly changed lines hit by tests — before approving.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-verify-tests-cover-changed-lines\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-verify-tests-cover-changed-lines\u002FSKILL.md",[],[197,198,199,200,201,202,203,37,204,205,206],"tests","cover","verify tests cover changed lines","verify","coverage","pr","exercise","patch","code","share"]