Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<img src="https://img.shields.io/badge/strategies-14-C9A84C" alt="Strategies" />
<img src="https://img.shields.io/badge/tests-483%20passing-brightgreen" alt="Tests" />
<img src="https://img.shields.io/badge/license-MIT-blue" alt="License" />
<img src="https://img.shields.io/badge/MCP-16%20tools-8A2BE2" alt="MCP" />
<img src="https://img.shields.io/badge/MCP-20%20tools-8A2BE2" alt="MCP" />
</p>

<p align="center">
Expand Down Expand Up @@ -75,6 +75,21 @@ hl run engine_mm -i ETH-PERP --tick 10 --mainnet
hl apex run --mainnet
```

### Funding Hedge

Propose a read-only BTCSWP funding-rate hedge from the CLI or any MCP client. The default `hl hedge propose` path reads the current account position; passing `--perp-notional` switches to pure sizing mode with no account fetch or order execution.

```bash
hl hedge info --json
hl hedge propose --asset BTC --side long --perp-notional 150000 --funding-apr 42
hl hedge propose --asset BTC --side long --perp-notional 150000 --funding-rate-8h 0.0003 --json
hl hedge backtest --csv funding.csv --asset BTC --side long --perp-notional 150000
```

Backtest CSVs need a `funding_rate_8h`, `perp_funding_rate_8h`, `funding_rate`, or `rate` column. Add `hedge_rate_8h`, `btcswp_rate_8h`, or `btcswp_funding_rate_8h` when you have realized BTCSWP rates; otherwise the backtest uses an idealized offset.

MCP tools: `funding_hedge_info`, `funding_hedge_propose`, `funding_hedge_backtest`

---

## Strategies
Expand Down Expand Up @@ -119,7 +134,7 @@ Supporting strategies for portfolio management, block liquidity, and autonomous

| Strategy | Description | Key Parameters | When to Use |
|----------|-------------|----------------|-------------|
| `hedge_agent` | Reduces excess exposure per deterministic mandate. Fires when net notional exceeds threshold. | `notional_threshold` | Always-on risk overlay. Pairs with any MM or signal strategy. |
| `hedge_agent` | Inventory exposure reducer. Fires when net notional exceeds threshold. This is not the BTCSWP funding-rate hedge; use `hl hedge propose` / `hl hedge backtest` for that. | `notional_threshold` | Always-on risk overlay. Pairs with any MM or signal strategy. |
| `rfq_agent` | Block-size dark RFQ liquidity — quotes for large orders with wider spreads. | `min_size`, `spread_bps` | Institutional/block flow. Provides hidden liquidity for large counterparties. |
| `claude_agent` | Multi-model LLM trading agent. Sends market snapshot to an LLM (Gemini, Claude, or OpenAI), receives structured trade decisions. | `model`, `base_size` | Experimental/research. Autonomous decision-making using LLM reasoning. |

Expand Down Expand Up @@ -154,6 +169,7 @@ Built on the open [Agent Skills](https://agentskills.io) standard. Each skill is
| **[Pulse](#pulse--emerging-pulse-detector)** | Detects sudden capital inflow via OI delta, volume surge, funding flips. IMMEDIATE signals at 100 confidence. | [`SKILL.md`](skills/pulse/SKILL.md) |
| **[Guard (Dynamic Stop Loss)](#guard--dynamic-stop-loss)** | 2-phase trailing stop with tiered profit-locking. ROE-based triggers that auto-account for leverage. | [`SKILL.md`](skills/guard/SKILL.md) |
| **[REFLECT](#reflect--performance-review)** | Nightly self-improvement loop. Analyzes every trade, finds patterns, generates actionable recommendations. | [`SKILL.md`](skills/reflect/SKILL.md) |
| **[BTCSWP Funding Hedge](#btcswp-funding-hedge)** | Thin wrapper over the MCP-exposed BTCSWP funding hedge calculator for BTC perp hedge proposals and backtests. | [`SKILL.md`](skills/btcswp-funding-hedge/SKILL.md) |

### Install a skill (agents)

Expand All @@ -166,6 +182,7 @@ https://raw.githubusercontent.com/Nunchi-trade/agent-cli/main/skills/radar/SKILL
https://raw.githubusercontent.com/Nunchi-trade/agent-cli/main/skills/pulse/SKILL.md
https://raw.githubusercontent.com/Nunchi-trade/agent-cli/main/skills/guard/SKILL.md
https://raw.githubusercontent.com/Nunchi-trade/agent-cli/main/skills/reflect/SKILL.md
https://raw.githubusercontent.com/Nunchi-trade/agent-cli/main/skills/btcswp-funding-hedge/SKILL.md
```

### Install a skill (OpenClaw / ClawHub)
Expand Down Expand Up @@ -351,6 +368,20 @@ All adjustments have guardrail bounds — parameters can't swing wildly. Disable

---

### BTCSWP Funding Hedge

Agent skill wrapper for the existing read-only BTCSWP funding hedge calculator exposed over MCP. It sizes BTC perp funding hedges without duplicating the math or placing orders.

```bash
hl hedge propose --asset BTC --side long --perp-notional 150000 --funding-apr 42 --json
```

MCP tools: `funding_hedge_info`, `funding_hedge_propose`, `funding_hedge_backtest`

**[Download SKILL.md](skills/btcswp-funding-hedge/SKILL.md)**

---

### Production Safety

Built-in safety systems that protect positions even when the runner process crashes.
Expand Down Expand Up @@ -460,6 +491,9 @@ hl radar run [options] # Opportunity radar
hl pulse run [options] # Pulse momentum detector
hl guard run -i ETH-PERP [options] # Guard trailing stop
hl reflect run [--since DATE] # Performance review
hl hedge info [--json] # Funding hedge profiles and schemas
hl hedge propose [options] # BTCSWP funding hedge proposal
hl hedge backtest --csv <path> # Local funding hedge cashflow backtest

# Infrastructure
hl builder approve [--mainnet] # Approve builder fee
Expand All @@ -481,7 +515,7 @@ hl mcp serve # stdio transport (default)
hl mcp serve --transport sse # SSE transport
```

**17 tools exposed:** `account`, `status`, `trade`, `run_strategy`, `strategies`, `radar_run`, `apex_status`, `apex_run`, `reflect_run`, `setup_check`, `builder_status`, `wallet_list`, `wallet_auto`, `agent_memory`, `trade_journal`, `judge_report`, `obsidian_context`
**20 tools exposed:** `account`, `status`, `trade`, `run_strategy`, `strategies`, `funding_hedge_info`, `funding_hedge_propose`, `funding_hedge_backtest`, `radar_run`, `apex_status`, `apex_run`, `reflect_run`, `setup_check`, `builder_status`, `wallet_list`, `wallet_auto`, `agent_memory`, `trade_journal`, `judge_report`, `obsidian_context`

Fast tools (strategies, builder, wallet, setup, memory, journal, judge) call Python directly — zero subprocess overhead.

Expand Down Expand Up @@ -618,7 +652,7 @@ hl run engine_mm -i BTCSWP-USDYP --tick 10
```
cli/ CLI commands and trading engine
commands/ Subcommand modules (run, apex, radar, pulse, guard, reflect, house, ...)
mcp_server.py MCP server (16 tools via FastMCP)
mcp_server.py MCP server (20 tools via FastMCP)
hl_adapter.py Direct HL API adapter (live + mock)
builder_fee.py Builder fee config (HL native BuilderInfo)
keystore.py Encrypted keystore (geth-compatible)
Expand Down
102 changes: 101 additions & 1 deletion cli/commands/hedge.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,76 @@ def _build_proposal(hl, coin: str):
return proposal, snapshot


# ─── info ────────────────────────────────────────────────────────────────────


@hedge_app.command("info")
def info_cmd(
json_output: bool = typer.Option(False, "--json", help="Output machine-readable JSON."),
):
"""Show deployed funding hedge capabilities and agent-facing schemas."""
from modules.funding_hedge import format_info, funding_hedge_info

info = funding_hedge_info()
if json_output:
typer.echo(json.dumps(info, indent=2))
else:
typer.echo(format_info(info))


# ─── propose ─────────────────────────────────────────────────────────────────


@hedge_app.command("propose")
def propose_cmd(
coin: str = typer.Argument("BTC", help="Coin to hedge (BTC, ETH)"),
asset: Optional[str] = typer.Option(None, "--asset", help="Alias for coin in pure sizing mode."),
mainnet: bool = typer.Option(False, "--mainnet", help="Use mainnet (default: testnet)"),
side: str = typer.Option("long", "--side", help="Perp exposure side for pure sizing: long or short"),
perp_notional: Optional[float] = typer.Option(
None,
"--perp-notional",
help="Pure sizing mode: absolute perp notional in USD; does not fetch account state.",
),
funding_apr: Optional[float] = typer.Option(
None,
"--funding-apr",
help="Pure sizing mode: annualized funding APR. Accepts 0.42 or 42 for 42%.",
),
funding_rate_8h: Optional[float] = typer.Option(
None,
"--funding-rate-8h",
help="Pure sizing mode: 8h funding rate as a decimal, e.g. 0.0003.",
),
vol_multiplier: float = typer.Option(15.0, "--vol-multiplier", help="BTCSWP hedge multiplier."),
json_output: bool = typer.Option(False, "--json", help="Output machine-readable JSON in pure sizing mode."),
):
"""Show a CFI v2 hedge proposal without executing."""
"""Show a CFI v2 hedge proposal without executing.

By default this reads the current account position. Passing
`--perp-notional` switches to pure sizing mode for agents/docs/tests.
"""
if perp_notional is not None:
from modules.funding_hedge import format_proposal, propose_funding_hedge

try:
proposal = propose_funding_hedge(
asset=asset or coin,
perp_side=side,
perp_notional_usd=perp_notional,
funding_apr=funding_apr,
funding_rate_8h=funding_rate_8h,
vol_multiplier=vol_multiplier,
)
except ValueError as exc:
raise typer.BadParameter(str(exc)) from exc

if json_output:
typer.echo(json.dumps(proposal.to_dict(), indent=2))
else:
typer.echo(format_proposal(proposal))
return

_boot_cli()

from cli.config import TradingConfig
Expand Down Expand Up @@ -379,8 +440,26 @@ def _refresh():
@hedge_app.command("backtest")
def backtest_cmd(
coin: str = typer.Option("BTC", "--coin", help="Coin (BTC or ETH)"),
asset: Optional[str] = typer.Option(None, "--asset", help="Alias for --coin in --csv mode."),
days: int = typer.Option(365, "--days", help="Backtest window"),
notional: float = typer.Option(1_000_000, "--notional", "-n"),
csv_path: Optional[Path] = typer.Option(
None,
"--csv",
exists=True,
file_okay=True,
dir_okay=False,
readable=True,
help="Pure local cashflow mode: CSV with funding_rate_8h/funding_rate and optional hedge_rate_8h.",
),
side: str = typer.Option("long", "--side", help="Perp exposure side for --csv mode: long or short"),
perp_notional: Optional[float] = typer.Option(
None,
"--perp-notional",
help="Pure --csv mode: absolute perp notional in USD; overrides --notional.",
),
vol_multiplier: float = typer.Option(15.0, "--vol-multiplier", help="BTCSWP hedge multiplier for --csv mode."),
json_output: bool = typer.Option(False, "--json", help="Output machine-readable JSON in --csv mode."),
script: Optional[Path] = typer.Option(
None,
"--script",
Expand All @@ -391,7 +470,28 @@ def backtest_cmd(

Shells out to `~/hyperliquid-funding-rate-perps/tools/hedge_calculator.py
--backtest --asset {COIN} --notional {N}`. Output is streamed through.
Passing `--csv` switches to pure local cashflow mode.
"""
if csv_path is not None:
from modules.funding_hedge import backtest_funding_hedge_csv, format_backtest

try:
backtest = backtest_funding_hedge_csv(
csv_path=csv_path,
asset=asset or coin,
perp_side=side,
perp_notional_usd=perp_notional if perp_notional is not None else notional,
vol_multiplier=vol_multiplier,
)
except ValueError as exc:
raise typer.BadParameter(str(exc)) from exc

if json_output:
typer.echo(json.dumps(backtest.to_dict(), indent=2))
else:
typer.echo(format_backtest(backtest))
return

_boot_cli()

script_path = script or (
Expand Down
20 changes: 20 additions & 0 deletions cli/commands/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def setup_check():

issues = []
ok_items = []
warnings = []

# 1. Python + hyperliquid SDK
try:
Expand All @@ -30,9 +31,16 @@ def setup_check():
# 2. Private key
has_env_key = bool(os.environ.get("HL_PRIVATE_KEY"))
from cli.keystore import list_keystores
from cli.web_auth import pairing_from_env
has_keystore = len(list_keystores()) > 0
pairing = pairing_from_env()
if has_env_key:
ok_items.append("HL_PRIVATE_KEY set")
if pairing is None:
warnings.append(
"Raw-key mode active. For MCP/agent use, prefer `hl pair connect` or hosted Nunchi Auth "
"so the AI client receives scoped access instead of a private key."
)
elif has_keystore:
ok_items.append(f"Keystore found ({len(list_keystores())} keys)")
from cli.keystore import _load_env_password
Expand All @@ -44,6 +52,13 @@ def setup_check():
issues.append("HL_KEYSTORE_PASSWORD not set (needed for auto-unlock)")
else:
issues.append("No private key: set HL_PRIVATE_KEY or run 'hl wallet import'")
if pairing is not None:
ok_items.append(f"web-auth pairing context provided ({pairing.address})")
else:
warnings.append(
"No web-auth pairing context found. Hosted/keyless signing uses "
"NUNCHI_WEB_AUTH_PAIR_TOKEN and NUNCHI_WEB_AUTH_ADDRESS."
)

# 3. Network
testnet = os.environ.get("HL_TESTNET", "true").lower()
Expand Down Expand Up @@ -86,6 +101,11 @@ def setup_check():
else:
typer.echo("\nAll checks passed.")

if warnings:
typer.echo("")
for warning in warnings:
typer.echo(f" WARN {warning}")


@setup_app.command("bootstrap")
def setup_bootstrap():
Expand Down
Loading