fix: use rolling_window_ticker for symbol-specific queries, expand window choices

- Replace removed Spot.ticker() with rolling_window_ticker for symbol-specific
ticker stats (compatible with binance-connector>=3.12.0).
- Fall back to ticker_24hr for full-market scans where rolling_window_ticker
requires symbols.
- Expand --window choices from [1h,4h,1d] to full Binance rolling window set:
1m,2m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,2d,3d,5d,7d,15d,30d.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-20 23:18:28 +08:00
parent 69f447f538
commit a9f6cf4c46
4 changed files with 17 additions and 7 deletions

View File

@@ -19,6 +19,12 @@
---
## What's New in 3.0.1
- **Fix ticker API compatibility** — `rolling_window_ticker` replaces the removed `ticker` method in `binance-connector>=3.12.0`.
- **Expand ticker window choices** — `market tickers --window` now supports `1m`, `2m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `6h`, `8h`, `12h`, `1d`, `2d`, `3d`, `5d`, `7d`, `15d`, `30d`.
- **Smart API fallback** — full-market scan (no symbols) falls back to 24h ticker; symbol-specific queries use rolling window.
## What's New in 3.0
- **Split decision models** — portfolio (add/hold/trim/exit) and opportunity (enter/watch/skip) now use independent scoring logic.

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "coinhunter"
version = "3.0.0"
version = "3.0.1"
description = "Binance-first trading CLI for balances, market data, opportunity scanning, and execution."
readme = "README.md"
license = {text = "MIT"}

View File

@@ -53,13 +53,15 @@ class SpotBinanceClient:
return self._call("exchange info", self._client.exchange_info, **kwargs) # type: ignore[no-any-return]
def ticker_stats(self, symbols: list[str] | None = None, *, window: str = "1d") -> list[dict[str, Any]]:
kwargs: dict[str, Any] = {"windowSize": window}
if symbols:
kwargs: dict[str, Any] = {"windowSize": window}
if len(symbols) == 1:
kwargs["symbol"] = symbols[0]
else:
kwargs["symbols"] = symbols
response = self._call("ticker stats", self._client.ticker, **kwargs)
response = self._call("ticker stats", self._client.rolling_window_ticker, **kwargs)
else:
response = self._call("ticker stats", self._client.ticker_24hr)
return response if isinstance(response, list) else [response]
def ticker_price(self, symbols: list[str] | None = None) -> list[dict[str, Any]]:

View File

@@ -157,7 +157,7 @@ Fields:
last_price latest traded price (float)
price_change_pct change % over the selected window (float, e.g. 2.5 = +2.5%)
quote_volume quote volume over the selected window (float)
window statistics window (enum: 1h, 4h, 1d)
window statistics window (enum: 1m, 2m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 2d, 3d, 5d, 7d, 15d, 30d)
""",
"json": """\
JSON Output:
@@ -172,7 +172,7 @@ Fields:
last_price latest traded price (float)
price_change_pct change % over the selected window (float, e.g. 2.5 = +2.5%)
quote_volume quote volume over the selected window (float)
window statistics window (enum: 1h, 4h, 1d)
window statistics window (enum: 1m, 2m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 2d, 3d, 5d, 7d, 15d, 30d)
""",
},
"market/klines": {
@@ -736,8 +736,10 @@ def build_parser() -> argparse.ArgumentParser:
)
tickers_parser.add_argument("symbols", nargs="+", metavar="SYM", help="Symbols to query (e.g. BTCUSDT ETH/USDT)")
tickers_parser.add_argument(
"-w", "--window", choices=["1h", "4h", "1d"], default="1d",
help="Statistics window: 1h, 4h, 1d (default: 1d)",
"-w", "--window",
choices=["1m", "2m", "5m", "15m", "30m", "1h", "2h", "4h", "6h", "8h", "12h", "1d", "2d", "3d", "5d", "7d", "15d", "30d"],
default="1d",
help="Rolling statistics window (default: 1d)",
)
_add_global_flags(tickers_parser)
klines_parser = market_subparsers.add_parser(