Skip to content
Merged
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
10 changes: 8 additions & 2 deletions keel/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,13 @@ def run_once(
# PAPER path instead, which never touches the broker. Constructed once per cycle and
# rehydrated from the orders table, so a per-cycle agent resumes its open positions.
paper_trader = PaperTrader(repo) if config.auto_trade.mode == "paper" else None
log_event(logger, logging.INFO, "agent.mode_resolved", mode=mode)
# What this cycle actually DID, for the log line and `LoopResult`. `_effective_mode`
# returns the executor string `"confirm"` for any non-live config -- paper included --
# so reporting it verbatim told the user a confirm-mode (live) run happened when the
# cycle only ever hit the paper path. `executor.execute`/`_handle_exits` still get the
# real executor `mode`; only what we surface to the user changes.
reported_mode = "paper" if paper_trader is not None else mode
log_event(logger, logging.INFO, "agent.mode_resolved", mode=reported_mode)
max_age_sec = config.auto_trade.interval_sec * FEED_STALENESS_CYCLES
finest = _finest_granularity(granularities)

Expand Down Expand Up @@ -792,7 +798,7 @@ def run_once(
ts=now_ts,
skipped=False,
skip_reason=None,
mode=mode,
mode=reported_mode,
polled=polled,
products=products,
stale_products=stale_products,
Expand Down
16 changes: 16 additions & 0 deletions tests/test_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,22 @@ def test_paper_mode_places_nothing_even_when_autonomous(repo):
assert broker.place_calls == [], "paper mode must never reach the broker"


def test_paper_mode_is_reported_as_paper_not_confirm(repo):
"""The loop summary must name the real operating mode.

Paper routes to the paper path and never touches the broker, but `_effective_mode` returns
the executor string `"confirm"` for any non-live config -- so a paper cycle used to report
`mode=confirm`, telling the user a confirm-mode (live) run happened when nothing did. The
reported mode must say `"paper"`.
"""
broker = FakeBroker(series={(PRODUCT, Granularity.ONE_DAY): [_candle(0, "100")]})
config = _config(auto_trade=AutoTradeConfig(mode="paper", interval_sec=50_000))

result = run_once(broker, repo, config, now_ts=90_000)

assert result.mode == "paper"


# -- run_once: EXIT wiring on a held position ---------------------------------------------------


Expand Down
Loading