feat: polish exec cli ergonomics and output
This commit is contained in:
65
README.md
65
README.md
@@ -78,6 +78,8 @@ coinhunter --help
|
|||||||
coinhunter --version
|
coinhunter --version
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Short aliases are available for the most common commands. The original long-form command names remain supported for backward compatibility.
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
Initialize user state:
|
Initialize user state:
|
||||||
@@ -90,13 +92,13 @@ Inspect runtime wiring:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
coinhunter paths
|
coinhunter paths
|
||||||
coinhunter doctor
|
coinhunter diag
|
||||||
```
|
```
|
||||||
|
|
||||||
Validate exchange credentials:
|
Validate exchange credentials:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
coinhunter check-api
|
coinhunter api-check
|
||||||
```
|
```
|
||||||
|
|
||||||
Run precheck / gate plumbing:
|
Run precheck / gate plumbing:
|
||||||
@@ -105,30 +107,48 @@ Run precheck / gate plumbing:
|
|||||||
coinhunter precheck
|
coinhunter precheck
|
||||||
coinhunter precheck --mark-run-requested "external-gate queued cron run"
|
coinhunter precheck --mark-run-requested "external-gate queued cron run"
|
||||||
coinhunter precheck --ack "analysis finished"
|
coinhunter precheck --ack "analysis finished"
|
||||||
|
coinhunter gate
|
||||||
```
|
```
|
||||||
|
|
||||||
Inspect balances or execute trading actions:
|
Inspect balances or execute trading actions:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
coinhunter smart-executor balances
|
coinhunter exec bal
|
||||||
coinhunter smart-executor status
|
coinhunter exec overview
|
||||||
coinhunter smart-executor hold
|
coinhunter exec hold
|
||||||
coinhunter smart-executor buy ENJUSDT 50
|
coinhunter exec buy ENJUSDT 50
|
||||||
coinhunter smart-executor sell-all ENJUSDT
|
coinhunter exec flat ENJUSDT
|
||||||
|
coinhunter exec rotate PEPEUSDT ETHUSDT
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Preferred `exec` verbs are `bal`, `overview`, `hold`, `buy`, `flat`, and `rotate`.
|
||||||
|
Legacy forms remain supported for backward compatibility: `balances`, `balance`, `acct`, `status`, `sell-all`, `sell_all`, and `rebalance`.
|
||||||
|
|
||||||
Generate review data:
|
Generate review data:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
coinhunter review-context 12
|
coinhunter review 12
|
||||||
coinhunter review-engine 12
|
coinhunter recap 12
|
||||||
```
|
```
|
||||||
|
|
||||||
Probe external market data:
|
Probe external market data:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
coinhunter probe bybit-ticker BTCUSDT
|
||||||
|
coinhunter probe bybit-klines BTCUSDT 60 20
|
||||||
|
```
|
||||||
|
|
||||||
|
Long-form equivalents still work:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
coinhunter doctor
|
||||||
|
coinhunter check-api
|
||||||
|
coinhunter smart-executor bal
|
||||||
|
coinhunter review-context 12
|
||||||
|
coinhunter review-engine 12
|
||||||
coinhunter market-probe bybit-ticker BTCUSDT
|
coinhunter market-probe bybit-ticker BTCUSDT
|
||||||
coinhunter market-probe bybit-klines BTCUSDT 60 20
|
coinhunter external-gate
|
||||||
|
coinhunter rotate-external-gate-log
|
||||||
```
|
```
|
||||||
|
|
||||||
## Runtime model
|
## Runtime model
|
||||||
@@ -159,34 +179,37 @@ Credential loading:
|
|||||||
### Diagnostics
|
### Diagnostics
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
coinhunter doctor
|
coinhunter diag
|
||||||
coinhunter paths
|
coinhunter paths
|
||||||
coinhunter check-api
|
coinhunter api-check
|
||||||
```
|
```
|
||||||
|
|
||||||
### Trading and execution
|
### Trading and execution
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
coinhunter smart-executor balances
|
coinhunter exec bal
|
||||||
coinhunter smart-executor status
|
coinhunter exec overview
|
||||||
coinhunter smart-executor hold
|
coinhunter exec hold
|
||||||
coinhunter smart-executor rebalance FROMUSDT TOUSDT
|
coinhunter exec buy ENJUSDT 50
|
||||||
|
coinhunter exec flat ENJUSDT
|
||||||
|
coinhunter exec rotate FROMUSDT TOUSDT
|
||||||
```
|
```
|
||||||
|
|
||||||
### Precheck and orchestration
|
### Precheck and orchestration
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
coinhunter precheck
|
coinhunter precheck
|
||||||
coinhunter external-gate
|
coinhunter gate
|
||||||
coinhunter rotate-external-gate-log
|
coinhunter rotate-gate-log
|
||||||
|
coinhunter rotate-log
|
||||||
```
|
```
|
||||||
|
|
||||||
### Review and market research
|
### Review and market research
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
coinhunter review-context 12
|
coinhunter review 12
|
||||||
coinhunter review-engine 12
|
coinhunter recap 12
|
||||||
coinhunter market-probe bybit-ticker BTCUSDT
|
coinhunter probe bybit-ticker BTCUSDT
|
||||||
```
|
```
|
||||||
|
|
||||||
## Development notes
|
## Development notes
|
||||||
|
|||||||
@@ -23,6 +23,41 @@ MODULE_MAP = {
|
|||||||
"auto-trader": "auto_trader",
|
"auto-trader": "auto_trader",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALIASES = {
|
||||||
|
"api-check": "check-api",
|
||||||
|
"diag": "doctor",
|
||||||
|
"gate": "external-gate",
|
||||||
|
"probe": "market-probe",
|
||||||
|
"review": "review-context",
|
||||||
|
"recap": "review-engine",
|
||||||
|
"rotate-gate-log": "rotate-external-gate-log",
|
||||||
|
"rotate-log": "rotate-external-gate-log",
|
||||||
|
"exec": "smart-executor",
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HELP = [
|
||||||
|
("api-check", "check-api", "Validate exchange/API connectivity"),
|
||||||
|
("diag", "doctor", "Inspect runtime wiring and diagnostics"),
|
||||||
|
("gate", "external-gate", "Run external gate orchestration"),
|
||||||
|
("init", None, "Initialize user runtime state"),
|
||||||
|
("paths", None, "Print runtime path resolution"),
|
||||||
|
("precheck", None, "Run precheck workflow"),
|
||||||
|
("probe", "market-probe", "Query external market data"),
|
||||||
|
("review", "review-context", "Generate review context"),
|
||||||
|
("recap", "review-engine", "Generate review recap/engine output"),
|
||||||
|
("rotate-gate-log, rotate-log", "rotate-external-gate-log", "Rotate external gate logs"),
|
||||||
|
("exec", "smart-executor", "Trading and execution actions"),
|
||||||
|
("auto-trader", None, "Auto trader entrypoint"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _command_listing() -> str:
|
||||||
|
lines = []
|
||||||
|
for names, canonical, summary in COMMAND_HELP:
|
||||||
|
label = names if canonical is None else f"{names} (alias for {canonical})"
|
||||||
|
lines.append(f" {label:<45} {summary}")
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
class VersionAction(argparse.Action):
|
class VersionAction(argparse.Action):
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
@@ -36,34 +71,46 @@ def build_parser() -> argparse.ArgumentParser:
|
|||||||
description="CoinHunter trading operations CLI",
|
description="CoinHunter trading operations CLI",
|
||||||
formatter_class=argparse.RawTextHelpFormatter,
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
epilog=(
|
epilog=(
|
||||||
|
"Commands:\n"
|
||||||
|
f"{_command_listing()}\n\n"
|
||||||
"Examples:\n"
|
"Examples:\n"
|
||||||
" coinhunter doctor\n"
|
" coinhunter diag\n"
|
||||||
" coinhunter paths\n"
|
" coinhunter paths\n"
|
||||||
" coinhunter check-api\n"
|
" coinhunter api-check\n"
|
||||||
" coinhunter smart-executor balances\n"
|
" coinhunter exec bal\n"
|
||||||
" coinhunter smart-executor hold\n"
|
" coinhunter exec overview\n"
|
||||||
" coinhunter smart-executor --analysis '...' --reasoning '...' buy ENJUSDT 50\n"
|
" coinhunter exec hold\n"
|
||||||
|
" coinhunter exec --analysis '...' --reasoning '...' buy ENJUSDT 50\n"
|
||||||
" coinhunter precheck\n"
|
" coinhunter precheck\n"
|
||||||
" coinhunter precheck --ack '分析完成:HOLD'\n"
|
" coinhunter precheck --ack '分析完成:HOLD'\n"
|
||||||
" coinhunter external-gate\n"
|
" coinhunter gate\n"
|
||||||
" coinhunter review-context 12\n"
|
" coinhunter review 12\n"
|
||||||
" coinhunter market-probe bybit-ticker BTCUSDT\n"
|
" coinhunter recap 12\n"
|
||||||
|
" coinhunter probe bybit-ticker BTCUSDT\n"
|
||||||
" coinhunter init\n"
|
" coinhunter init\n"
|
||||||
|
"\n"
|
||||||
|
"Preferred exec verbs are bal, overview, hold, buy, flat, and rotate.\n"
|
||||||
|
"Legacy command names remain supported for backward compatibility.\n"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument("--version", nargs=0, action=VersionAction, help="Print installed version and exit")
|
parser.add_argument("--version", nargs=0, action=VersionAction, help="Print installed version and exit")
|
||||||
parser.add_argument("command", nargs="?", choices=sorted(MODULE_MAP.keys()), help="CoinHunter command to run")
|
parser.add_argument(
|
||||||
|
"command",
|
||||||
|
nargs="?",
|
||||||
|
metavar="COMMAND",
|
||||||
|
help="Command to run. Use --help to see canonical names and short aliases.",
|
||||||
|
)
|
||||||
parser.add_argument("args", nargs=argparse.REMAINDER)
|
parser.add_argument("args", nargs=argparse.REMAINDER)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
def run_python_module(module_name: str, argv: list[str]) -> int:
|
def run_python_module(module_name: str, argv: list[str], display_name: str) -> int:
|
||||||
module = importlib.import_module(f".{module_name}", package="coinhunter")
|
module = importlib.import_module(f".{module_name}", package="coinhunter")
|
||||||
if not hasattr(module, "main"):
|
if not hasattr(module, "main"):
|
||||||
raise RuntimeError(f"Module {module_name} has no main()")
|
raise RuntimeError(f"Module {module_name} has no main()")
|
||||||
old_argv = sys.argv[:]
|
old_argv = sys.argv[:]
|
||||||
try:
|
try:
|
||||||
sys.argv = [f"coinhunter {module_name}", *argv]
|
sys.argv = [display_name, *argv]
|
||||||
result = module.main()
|
result = module.main()
|
||||||
return int(result) if isinstance(result, int) else 0
|
return int(result) if isinstance(result, int) else 0
|
||||||
except SystemExit as exc:
|
except SystemExit as exc:
|
||||||
@@ -78,11 +125,16 @@ def main() -> int:
|
|||||||
if not parsed.command:
|
if not parsed.command:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 0
|
return 0
|
||||||
module_name = MODULE_MAP[parsed.command]
|
command = ALIASES.get(parsed.command, parsed.command)
|
||||||
|
if command not in MODULE_MAP:
|
||||||
|
parser.error(
|
||||||
|
f"invalid command: {parsed.command!r}. Use `coinhunter --help` to see supported commands and aliases."
|
||||||
|
)
|
||||||
|
module_name = MODULE_MAP[command]
|
||||||
argv = list(parsed.args)
|
argv = list(parsed.args)
|
||||||
if argv and argv[0] == "--":
|
if argv and argv[0] == "--":
|
||||||
argv = argv[1:]
|
argv = argv[1:]
|
||||||
return run_python_module(module_name, argv)
|
return run_python_module(module_name, argv, f"coinhunter {parsed.command}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -2,47 +2,101 @@
|
|||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
COMMAND_CANONICAL = {
|
||||||
|
"bal": "balances",
|
||||||
|
"balances": "balances",
|
||||||
|
"balance": "balances",
|
||||||
|
"acct": "status",
|
||||||
|
"overview": "status",
|
||||||
|
"status": "status",
|
||||||
|
"hold": "hold",
|
||||||
|
"buy": "buy",
|
||||||
|
"flat": "sell-all",
|
||||||
|
"sell-all": "sell-all",
|
||||||
|
"sell_all": "sell-all",
|
||||||
|
"rotate": "rebalance",
|
||||||
|
"rebalance": "rebalance",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def add_shared_options(parser: argparse.ArgumentParser) -> None:
|
||||||
|
parser.add_argument("--decision-id", help="Override the decision ID; otherwise one is derived automatically")
|
||||||
|
parser.add_argument("--analysis", help="Persist analysis text with the execution record")
|
||||||
|
parser.add_argument("--reasoning", help="Persist reasoning text with the execution record")
|
||||||
|
parser.add_argument("--dry-run", action="store_true", help="Simulate the command without placing live orders")
|
||||||
|
|
||||||
|
|
||||||
def build_parser() -> argparse.ArgumentParser:
|
def build_parser() -> argparse.ArgumentParser:
|
||||||
|
shared = argparse.ArgumentParser(add_help=False)
|
||||||
|
add_shared_options(shared)
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Coin Hunter Smart Executor",
|
prog="coinhunter exec",
|
||||||
|
description="Professional execution console for account inspection and spot trading workflows",
|
||||||
formatter_class=argparse.RawTextHelpFormatter,
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
|
parents=[shared],
|
||||||
epilog=(
|
epilog=(
|
||||||
"示例:\n"
|
"Preferred verbs:\n"
|
||||||
" python smart_executor.py hold\n"
|
" bal Print live balances as stable JSON\n"
|
||||||
" python smart_executor.py sell-all ETHUSDT\n"
|
" overview Print balances, positions, and market snapshot as stable JSON\n"
|
||||||
" python smart_executor.py buy ENJUSDT 100\n"
|
" hold Record a hold decision without trading\n"
|
||||||
" python smart_executor.py rebalance PEPEUSDT ETHUSDT\n"
|
" buy SYMBOL USDT Buy a symbol using a USDT notional amount\n"
|
||||||
" python smart_executor.py balances\n\n"
|
" flat SYMBOL Exit an entire symbol position\n"
|
||||||
"兼容旧调用:\n"
|
" rotate FROM TO Rotate exposure from one symbol into another\n\n"
|
||||||
" python smart_executor.py HOLD\n"
|
"Examples:\n"
|
||||||
" python smart_executor.py --decision HOLD --dry-run\n"
|
" coinhunter exec bal\n"
|
||||||
|
" coinhunter exec overview\n"
|
||||||
|
" coinhunter exec hold\n"
|
||||||
|
" coinhunter exec buy ENJUSDT 100\n"
|
||||||
|
" coinhunter exec flat ENJUSDT --dry-run\n"
|
||||||
|
" coinhunter exec rotate PEPEUSDT ETHUSDT\n\n"
|
||||||
|
"Legacy forms remain supported for backward compatibility:\n"
|
||||||
|
" balances, balance -> bal\n"
|
||||||
|
" acct, status -> overview\n"
|
||||||
|
" sell-all, sell_all -> flat\n"
|
||||||
|
" rebalance -> rotate\n"
|
||||||
|
" HOLD / BUY / SELL_ALL / REBALANCE via --decision are still accepted\n"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument("--decision-id", help="Override decision id (otherwise derived automatically)")
|
subparsers = parser.add_subparsers(
|
||||||
parser.add_argument("--analysis", help="Decision analysis text to persist into logs")
|
dest="command",
|
||||||
parser.add_argument("--reasoning", help="Decision reasoning text to persist into logs")
|
metavar="{bal,overview,hold,buy,flat,rotate,...}",
|
||||||
parser.add_argument("--dry-run", action="store_true", help="Force dry-run mode for this invocation")
|
)
|
||||||
|
|
||||||
subparsers = parser.add_subparsers(dest="command")
|
subparsers.add_parser("bal", parents=[shared], help="Preferred: print live balances as stable JSON")
|
||||||
|
subparsers.add_parser("overview", parents=[shared], help="Preferred: print the account overview as stable JSON")
|
||||||
|
subparsers.add_parser("hold", parents=[shared], help="Preferred: record a hold decision without trading")
|
||||||
|
|
||||||
subparsers.add_parser("hold", help="Log a HOLD decision without trading")
|
buy = subparsers.add_parser("buy", parents=[shared], help="Preferred: buy a symbol with a USDT notional amount")
|
||||||
subparsers.add_parser("balances", help="Print live balances as JSON")
|
|
||||||
subparsers.add_parser("balance", help="Alias of balances")
|
|
||||||
subparsers.add_parser("status", help="Print balances + positions + snapshot as JSON")
|
|
||||||
|
|
||||||
sell_all = subparsers.add_parser("sell-all", help="Sell all of one symbol")
|
|
||||||
sell_all.add_argument("symbol")
|
|
||||||
sell_all_legacy = subparsers.add_parser("sell_all", help=argparse.SUPPRESS)
|
|
||||||
sell_all_legacy.add_argument("symbol")
|
|
||||||
|
|
||||||
buy = subparsers.add_parser("buy", help="Buy symbol with USDT amount")
|
|
||||||
buy.add_argument("symbol")
|
buy.add_argument("symbol")
|
||||||
buy.add_argument("amount_usdt", type=float)
|
buy.add_argument("amount_usdt", type=float)
|
||||||
|
|
||||||
rebalance = subparsers.add_parser("rebalance", help="Sell one symbol and rotate to another")
|
flat = subparsers.add_parser("flat", parents=[shared], help="Preferred: exit an entire symbol position")
|
||||||
|
flat.add_argument("symbol")
|
||||||
|
|
||||||
|
rebalance = subparsers.add_parser("rotate", parents=[shared], help="Preferred: rotate exposure from one symbol into another")
|
||||||
rebalance.add_argument("from_symbol")
|
rebalance.add_argument("from_symbol")
|
||||||
rebalance.add_argument("to_symbol")
|
rebalance.add_argument("to_symbol")
|
||||||
|
|
||||||
|
subparsers.add_parser("balances", parents=[shared], help=argparse.SUPPRESS)
|
||||||
|
subparsers.add_parser("balance", parents=[shared], help=argparse.SUPPRESS)
|
||||||
|
subparsers.add_parser("acct", parents=[shared], help=argparse.SUPPRESS)
|
||||||
|
subparsers.add_parser("status", parents=[shared], help=argparse.SUPPRESS)
|
||||||
|
|
||||||
|
sell_all = subparsers.add_parser("sell-all", parents=[shared], help=argparse.SUPPRESS)
|
||||||
|
sell_all.add_argument("symbol")
|
||||||
|
sell_all_legacy = subparsers.add_parser("sell_all", parents=[shared], help=argparse.SUPPRESS)
|
||||||
|
sell_all_legacy.add_argument("symbol")
|
||||||
|
|
||||||
|
rebalance_legacy = subparsers.add_parser("rebalance", parents=[shared], help=argparse.SUPPRESS)
|
||||||
|
rebalance_legacy.add_argument("from_symbol")
|
||||||
|
rebalance_legacy.add_argument("to_symbol")
|
||||||
|
|
||||||
|
subparsers._choices_actions = [
|
||||||
|
action
|
||||||
|
for action in subparsers._choices_actions
|
||||||
|
if action.help != argparse.SUPPRESS
|
||||||
|
]
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@@ -53,6 +107,11 @@ def normalize_legacy_argv(argv: list[str]) -> list[str]:
|
|||||||
action_aliases = {
|
action_aliases = {
|
||||||
"HOLD": ["hold"],
|
"HOLD": ["hold"],
|
||||||
"hold": ["hold"],
|
"hold": ["hold"],
|
||||||
|
"bal": ["balances"],
|
||||||
|
"acct": ["status"],
|
||||||
|
"overview": ["status"],
|
||||||
|
"flat": ["sell-all"],
|
||||||
|
"rotate": ["rebalance"],
|
||||||
"SELL_ALL": ["sell-all"],
|
"SELL_ALL": ["sell-all"],
|
||||||
"sell_all": ["sell-all"],
|
"sell_all": ["sell-all"],
|
||||||
"sell-all": ["sell-all"],
|
"sell-all": ["sell-all"],
|
||||||
@@ -66,6 +125,8 @@ def normalize_legacy_argv(argv: list[str]) -> list[str]:
|
|||||||
"balances": ["balances"],
|
"balances": ["balances"],
|
||||||
"STATUS": ["status"],
|
"STATUS": ["status"],
|
||||||
"status": ["status"],
|
"status": ["status"],
|
||||||
|
"OVERVIEW": ["status"],
|
||||||
|
"overview": ["status"],
|
||||||
}
|
}
|
||||||
|
|
||||||
has_legacy_flag = any(t.startswith("--decision") for t in argv)
|
has_legacy_flag = any(t.startswith("--decision") for t in argv)
|
||||||
@@ -130,8 +191,7 @@ def parse_cli_args(argv: list[str]):
|
|||||||
if not args.command:
|
if not args.command:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
if args.command == "sell_all":
|
args.command = COMMAND_CANONICAL.get(args.command, args.command)
|
||||||
args.command = "sell-all"
|
|
||||||
return args, normalized
|
return args, normalized
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
"""Trade execution actions (buy, sell, rebalance, hold, status)."""
|
"""Trade execution actions (buy, sell, rebalance, hold, status)."""
|
||||||
|
import json
|
||||||
|
|
||||||
from ..logger import log_decision, log_trade
|
from ..logger import log_decision, log_trade
|
||||||
from .exchange_service import (
|
from .exchange_service import (
|
||||||
fetch_balances,
|
fetch_balances,
|
||||||
@@ -12,6 +14,10 @@ from .portfolio_service import load_positions, save_positions, upsert_position,
|
|||||||
from .trade_common import is_dry_run, USDT_BUFFER_PCT, log, bj_now_iso
|
from .trade_common import is_dry_run, USDT_BUFFER_PCT, log, bj_now_iso
|
||||||
|
|
||||||
|
|
||||||
|
def print_json(payload: dict) -> None:
|
||||||
|
print(json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True))
|
||||||
|
|
||||||
|
|
||||||
def build_decision_context(ex, action: str, argv_tail: list[str], decision_id: str):
|
def build_decision_context(ex, action: str, argv_tail: list[str], decision_id: str):
|
||||||
balances = fetch_balances(ex)
|
balances = fetch_balances(ex)
|
||||||
positions = load_positions()
|
positions = load_positions()
|
||||||
@@ -168,11 +174,12 @@ def command_status(ex):
|
|||||||
"positions": positions,
|
"positions": positions,
|
||||||
"market_snapshot": market_snapshot,
|
"market_snapshot": market_snapshot,
|
||||||
}
|
}
|
||||||
print(payload)
|
print_json(payload)
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
|
|
||||||
def command_balances(ex):
|
def command_balances(ex):
|
||||||
balances = fetch_balances(ex)
|
balances = fetch_balances(ex)
|
||||||
print({"balances": balances})
|
payload = {"balances": balances}
|
||||||
|
print_json(payload)
|
||||||
return balances
|
return balances
|
||||||
|
|||||||
Reference in New Issue
Block a user