mcpField
B
bison-strategy

bison-strategy

github.com/senpi-aiOther14061 installsUpdated today
Repository

About bison-strategy

bison-strategy is a conviction-based trading skill for BTC, ETH, and SOL. It scores market and smart-money factors, emits entry signals to the runtime, and leaves position exits to the DSL ratchet system.

Key features

  1. 01BTC, ETH, and SOL asset whitelist
  2. 02Conviction scoring with an 11-point floor
  3. 03Direction selected by a trend-first waterfall
  4. 04Runtime risk guard rails
  5. 05DSL ratchet exits without time-cuts

Use cases

  1. 01Screen whitelisted assets for conviction theses
  2. 02Select trade direction from trend and fallback signals
  3. 03Limit entries and losses through runtime controls
  4. 04Manage exits with a ratchet ladder

MCP support

The producer calls Senpi MCP through `SenpiClient.mcp_call()` and sends signals via `push_signal()` to the runtime. The runtime opens positions; DSL manages exits.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/senpi-ai/senpi-skills --skill bison-strategy

After installing, type/bison-strategyin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

README.md
runtime.yaml
config/
bison-config.json
references/
skill-attribution.md
scripts/
bison_config.py
bison-producer.py

Details

From the project README

🦬 BISON v3.0.1 — Conviction Holder

Asset whitelist (BTC/ETH/SOL). Conviction floor (minScore 11). No time-cuts — Phase 1 + Phase 2 ratchet ladder own all exits.

v3.0.1 (2026-05-18) — held-asset dedup race-fix + DSL throttle

Operational reliability patch. NO thesis change. NO scoring change.

Bug observed. Audit on Bison12 (M192943) 2026-05-13 to 2026-05-17 showed 16 create_position ENGINE_FAILUREs carrying BISON_CONVICTION reasoning text, all for assets the wallet already held. Each failure was a runtime LLM-gate fire on a producer-emitted signal that should have been deduped — the producer's on-chain heldAssets check leaked during the race window between push_signal() returning OK and the resulting position appearing in the next-tick clearinghouseState pull.

Fix 1 — recent-signals cache (scripts/bison_config.py). record_signal(coin) writes {coin: epoch_seconds} to state/recent-signals.json after every successful push. main() calls was_recently_signaled(coin) BEFORE build_thesis() and skips any coin seen within RECENT_SIGNAL_TTL_SEC (default 180s ≈ 3× the typical ALO open-fill window). Skipped coins are echoed in recently_signaled_skipped in the per-tick output for audit.

Fix 2 — DSL exit interval 30s → 60s (runtime.yaml). Audit also showed clusters of CLOSE_FEE_OPTIMIZED_FAILED "Reduce only order would increase position" + CLOSE_NO_POSITION errors firing 1-2 ticks after a successful close. The runtime's view of the closed position takes longer to refresh than the 30s DSL interval, so DSL re-fires close on a flat HL position. Doubling the interval gives the runtime position-state pull room to catch up and halves the wasted close attempts. Root cause (runtime- side position-state sync) is escalated to the runtime team — this YAML change is downstream mitigation only.

What this does NOT fix. Phantom orphan positions where DSL state and HL state are durably out of sync (i.e. runtime thinks a position is open after a complete external close, or vice versa). That class of bug needs runtime-side reconciliation; the producer has no authority over DSL state.

v3.0.0 (2026-05-12) — plumbing-only migration

NO thesis change. v2.1 asset whitelist, minScore 11, conviction-scaled margin tiers, direction waterfall, 9-component scoring, and DSL preset all preserved verbatim. Six-layer plumbing flip:

  1. MCP transport: mcporter subprocess (2.5-5s cold-start per call) → senpi_runtime_helpers.SenpiClient.mcp_call() in-process HTTPS (~280ms).
  2. Signal emit: scanner called create_position directly (Wolverine pattern); producer now emits via push_signal() to runtime /signals. Runtime LLM-gated bison_entry action opens via FEE_OPTIMIZED_LIMIT, passing marginUsd + leverage through from signal data for tier-based sizing.
  3. Reentrancy: no v2 lockfile to replace (Bison v2.x ran on openclaw cron with no producer-side lock); producer_daemon owns the per-tick scanner_lock with stale-PID auto-recovery.
  4. Scheduler: openclaw cron (5 min) → producer_daemon(interval_seconds=300). Long-lived process; zero per-tick cold-start cost.
  5. Risk gates: Python MAX_DAILY_LOSS_PCT, dynamic-slots PnL-based cap, per-asset cooldown state files → declarative risk.guard_rails block. state/trade-counter.json and state/asset-cooldowns.json are vestigial in v3.0 and can be deleted.
  6. Exit fee: DSL exits switched from MARKET (taker, 0.045%) to FEE_OPTIMIZED_LIMIT (maker-first, 0.015%, 60s ALO timeout, taker fallback). Entry exits keep ensure_execution_as_taker: false (v2.1 ALO patience rule).

CRITICAL RULES

RULE 1: Producer enters. DSL exits. Producer NEVER exits positions.

v1.x had thesis re-evaluation that chopped winners. v2.0 removed it. v3.0 makes it structurally impossible — the producer has no close_position call site.

RULE 2: Producer emits signals via push_signal(); runtime opens

The producer scores conviction theses and emits via client.push_signal(). The runtime's LLM-gated bison_entry action opens the position via FEE_OPTIMIZED_LIMIT with ensure_execution_as_taker: false (v2.1 patience rule preserved — entry ALO waits 30s for maker fill).

RULE 3: All signals are score contributors, not hard gates

4H trend, 1H trend, 1H momentum, SM direction, funding — all add/subtract points. The minScore threshold (v2.1+: 11) is the ONLY gate. Nothing kills a signal before scoring.

RULE 4: Asset whitelist enforced (v2.1+)

Only BTC/ETH/SOL by default (configurable via allowedAssets in bison-config.json). Pre-v2.1 fetched top 10 by 24h notional volume — let small-caps that volume-spiked into the universe (e.g. ZEC on May 4) consume the single daily slot.

RULE 5: ensureExecutionAsTaker = false on ENTRIES

Entries use FEE_OPTIMIZED_LIMIT with ensure_execution_as_taker: false (v2.1 patience rule). Exits use ensure_execution_as_taker: true (closes MUST happen — taker fallback is the safety floor).

RULE 6: Use the DSL preset in runtime.yaml — not a custom DSL state file

v2.x shipped a hardcoded DSL state template in scanner output. v3.0 uses the runtime YAML's dsl_preset block as the single source of truth. No scanner-side DSL state.

How BISON v3.0 trades

Entry (all score contributors — preserved from v2.1)
SignalPointsType
4H trend aligned+3Score
4H trend opposing-1Score
1H trend agrees+2Score
1H trend opposing-1Score
1H strong momentum (≥1%)+2Score
1H moderate momentum (≥0.5%)+1Score
1H counter momentum-1Score
SM aligned+2Score
SM opposing-2Score
Funding aligned+2Score
Funding crowded-1Score
Volume rising+1Score
OI growing+1Score
RSI room+1Score
RSI extreme-1Score
4H momentum (>1.5%)+1Score

Min score: 11. Max possible: ~16.

Direction determination (waterfall)
  1. 4H trend structure → LONG if BULLISH, SHORT if BEARISH
  2. If 4H NEUTRAL → follow SM direction
  3. If SM NEUTRAL → follow 1H momentum (>0.5%)
  4. If all neutral → no signal
Conviction-scaled margin
ScoreMargin
8-925% of account
10-1131%
12+37%

Producer computes marginUsd from tier; signal data carries it; LLM gate passes through to runtime payload. Same pattern for leverage (default 10x, MIN 7x, MAX 10x).

Exit — RatchetStop only

DSL preset wide-by-design for conviction breathing:

  • +10% ROE: no lock (confirms working)
  • +20% / +25% lock
  • +30% / +40% lock
  • +50% / +60% lock
  • +75% / +75% lock
  • +100% ROE: lock 85% — infinite trail

Phase 1 max_loss: 30%. Time-cuts: hard_timeout + dead_weight_cut DISABLED. weak_peak_cut KEPT (self-limiting at 60min/3.0% peak).

Risk gates (runtime.yaml risk.guard_rails)

GateSettingReplaces
max_entries_per_day3v2.1 base daily cap
per_asset_cooldown_minutes120v2.1 cooldownMinutes
daily_loss_limit_pct10v2.1 MAX_DAILY_LOSS_PCT
max_consecutive_losses3v2.1 (implicit)
cooldown_minutes (post-loss)30new (fleet-standard)
drawdown_halt_pct25new (fleet-standard, Roach lesson)
drawdown_reset_on_day_rolloverfalsefleet-standard

v2.1's PnL-aware dynamic daily cap (3 base / 6 hard cap, tiered by realized PnL) is dropped in favor of static max_entries_per_day=3 + drawdown_halt_pct=25. The conservative ceiling and -25% hard stop are preserved; the "ride the hot hand" tier is sacrificed for state-file-free reliability.

Hardcoded constants (not configurable)

  • MAX_LEVERAGE: 10
  • MIN_LEVERAGE: 7
  • XYZ_BANNED: true (banned at producer scan level)

Operator deployment topology

Bison's runtime + producer pair runs per strategy wallet, not per operator. Operators wanting more capital exposure deploy multiple strategy wallets, each running its own runtime instance and its own bison-producer daemon. Each instance:

  • Reads its own ${WALLET_ADDRESS} (typically via env var) — the runtime YAML's ${WALLET_ADDRESS} placeholder is resolved at runtime create time, and the producer falls back to bison-config.json's wallet field.
  • Computes held_assets from its own wallet's on-chain clearinghouseState — instances do NOT see each other's positions.
  • Writes its own state/recent-signals.json (per-instance cache).
  • Reuses the same SENPI_AUTH_TOKEN (operator-scoped) — a single operator can run N strategy wallets under one auth token.

Implication: two-wallet deployment doubles capital exposure and parallelizes asset selection. Wallet A may take SOL while Wallet B simultaneously takes BTC, capturing uncorrelated entries. Each wallet's DSL ratchet is independent.

This topology is the production reality on Bison's live deployment (see Predator MCP bison-v1-0 slug, strategyWalletCount: 2). It is NOT a Bison-specific feature — it's how the senpi-trading- runtime plugin natively scales: one runtime per wallet, multiple wallets per operator.

Signal cadence (what to expect)

  • Producer tick: every 300s (5 min). Long-lived daemon — no per-tick cold-start cost.
  • Universe scanned per tick: ≤ 10 assets, filtered to the whitelist (default BTC/ETH/SOL = 3 assets).
  • MCP cost per tick: ~4-7 calls (market_list_instruments, leaderboard_get_markets, market_get_asset_data per candidate, strategy_get_clearinghouse_state for held check).
  • Emission rate: 0-5 signals per day in typical regimes. The MIN_SCORE 11 floor + 2h per_asset_cooldown keeps emission selective.
  • Quiet day signature: every tick output ends with "note": "WAITING — no conviction thesis (min score 11)". This is the most common state — the producer is alive, the thesis is just not firing.
  • Suspected silent producer: check audit_query({tool_name: "market_get_asset_data", user_ids: [<MID>]}) — if entries fall to zero for >15 min during market hours, the daemon has died and needs disown re-launch (fleet pattern from 2026-05-13).

Reading the decision log

Bison emits per-trade decision telemetry via the runtime LLM gate. To inspect the reasoning chain for a specific window:

mcp__senpi-prod__audit_query({
  user_ids: ["<your Senpi MID>"],     # e.g. "M192943" for Bison12
  tool_name: "create_position",
  action_type: "create",
  limit: 50
})

Each entry's ai_reasoning field is the LLM gate's reasoning output — typically "BISON_CONVICTION <ASSET> <DIRECTION> - <top_score_reason>". Successful entries have success: true; failures carry an error_code and error_message.

Pair with close_position audit queries to see the DSL exit reasons (weak_peak_cut, dsl_breach, etc).

The audit-query path is the canonical post-hoc validation tool for Bison — the Predator MCP shows aggregates (PnL, ROI, volume) but does not expose per-trade reasoning. For "why did this trade fire" questions, always go to audit_query.

v3.0.0 (2026-05-12) — plumbing-only migration

Hard rule for user-conversation Claude sessions

User-conversation Claude sessions MUST NOT call: create_position, close_position, edit_position, ratchet_stop_add, ratchet_stop_edit, ratchet_stop_delete, cancel_order, strategy_close, strategy_close_positions.

These tools are reserved for the producer daemon (entry path) and the DSL ratchet engine (exit path). User-conversation sessions are read-only.

Operator install

See README.md for fresh-install + migration commands from v2.1.

Changelog

v3.0.0 (2026-05-12) — plumbing-only migration

Migrated to helpers-native (senpi_runtime_helpers). Thesis preserved verbatim. See six-layer flip above.

v2.1 (2026-05-07)
  • Asset whitelist (BTC/ETH/SOL); pre-v2.1 fetched top-10-by-volume which let small-caps like ZEC consume the daily slot
  • minScore 8 → 11; was firing on first mediocre setup post-midnight, now demands real conviction
  • DSL time-cuts disabled in runtime.yaml per single-asset pattern
v2.0 (2026-04-06)
  • ALL hard gates converted to score contributors
  • Thesis exit (evaluate_held_position) REMOVED
  • Scanner calls create_position internally (Wolverine pattern; superseded in v3.0 by helpers-native push_signal)
  • Direction waterfall: 4H → SM → 1H momentum

License

Apache-2.0 — attribution required for derivative works. Copyright 2026 Senpi (https://senpi.ai).

Skill Attribution

When creating a strategy, include skill_name and skill_version in the call. See references/skill-attribution.md for details.

Comments

Markdown supported