Fix live market time handling in strategy engine

This commit is contained in:
Thigazhezhilan J 2026-04-02 09:59:09 +05:30
parent f5bd36df64
commit 88ea093525
6 changed files with 44 additions and 31 deletions

View File

@ -4,12 +4,13 @@ import sys
import threading
from datetime import datetime, timedelta, timezone
from pathlib import Path
from zoneinfo import ZoneInfo
ENGINE_ROOT = Path(__file__).resolve().parents[3]
if str(ENGINE_ROOT) not in sys.path:
sys.path.append(str(ENGINE_ROOT))
from indian_paper_trading_strategy.engine.market import is_market_open, align_to_market_open
from indian_paper_trading_strategy.engine.market import is_market_open, align_to_market_open, market_now
from indian_paper_trading_strategy.engine.runner import start_engine, stop_engine
from indian_paper_trading_strategy.engine.state import init_paper_state, load_state, save_state
from indian_paper_trading_strategy.engine.broker import PaperBroker
@ -38,6 +39,7 @@ SEQ_LOCK = threading.Lock()
SEQ = 0
LAST_WAIT_LOG_TS = {}
WAIT_LOG_INTERVAL = timedelta(seconds=60)
IST = ZoneInfo("Asia/Kolkata")
def init_log_state():
global SEQ
@ -154,7 +156,7 @@ def _maybe_parse_json(value):
def _local_tz():
return datetime.now().astimezone().tzinfo
return IST
def _format_local_ts(value: datetime | None):
@ -290,7 +292,7 @@ def reactivate_strategy_config(user_id: str, run_id: str):
return cfg
def _write_status(user_id: str, run_id: str, status):
now_local = datetime.now().astimezone()
now_local = market_now()
with db_connection() as conn:
with conn:
with conn.cursor() as cur:
@ -755,7 +757,11 @@ def get_strategy_status(user_id: str):
if next_eligible:
try:
parsed_next = datetime.fromisoformat(next_eligible)
now_cmp = datetime.now(parsed_next.tzinfo) if parsed_next.tzinfo else datetime.now()
now_cmp = (
datetime.now(parsed_next.tzinfo)
if parsed_next.tzinfo
else market_now().replace(tzinfo=None)
)
if parsed_next > now_cmp:
status["status"] = "WAITING"
except ValueError:
@ -928,7 +934,7 @@ def _issue_is_stale_for_current_state(
return True
if event == "EXECUTION_BLOCKED" and reason_key == "market_closed":
return is_market_open(datetime.now())
return is_market_open(market_now())
if mode != "LIVE":
return False
@ -1026,7 +1032,7 @@ def get_strategy_summary(user_id: str):
return summary
def get_market_status():
now = datetime.now()
now = market_now()
return {
"status": "OPEN" if is_market_open(now) else "CLOSED",
"checked_at": now.isoformat(),

View File

@ -12,6 +12,7 @@ from psycopg2.extras import execute_values
from indian_paper_trading_strategy.engine.data import fetch_live_price
from indian_paper_trading_strategy.engine.db import db_connection, insert_engine_event, run_with_retry, get_context
from indian_paper_trading_strategy.engine.market import market_now
class Broker(ABC):
@ -50,7 +51,7 @@ class BrokerAuthExpired(BrokerError):
def _local_tz():
return datetime.now().astimezone().tzinfo
return market_now().tzinfo
def _format_utc_ts(value: datetime | None):

View File

@ -5,6 +5,7 @@ from indian_paper_trading_strategy.engine.state import load_state, save_state
from indian_paper_trading_strategy.engine.broker import Broker, BrokerAuthExpired
from indian_paper_trading_strategy.engine.ledger import log_event, event_exists
from indian_paper_trading_strategy.engine.db import insert_engine_event, run_with_retry
from indian_paper_trading_strategy.engine.market import market_now
from indian_paper_trading_strategy.engine.time_utils import compute_logical_time
def _as_float(value):
@ -21,7 +22,7 @@ def _as_float(value):
return float(value)
def _local_tz():
return datetime.now().astimezone().tzinfo
return market_now().tzinfo
def _normalize_now(now):

View File

@ -6,6 +6,10 @@ _MARKET_TZ = pytz.timezone("Asia/Kolkata")
_OPEN_T = dtime(9, 15)
_CLOSE_T = dtime(15, 30)
def market_now() -> datetime:
return datetime.now(_MARKET_TZ)
def _as_market_tz(value: datetime) -> datetime:
if value.tzinfo is None:
return _MARKET_TZ.localize(value)
@ -16,7 +20,7 @@ def is_market_open(now: datetime) -> bool:
return now.weekday() < 5 and _OPEN_T <= now.time() <= _CLOSE_T
def india_market_status():
now = datetime.now(_MARKET_TZ)
now = market_now()
return is_market_open(now), now

View File

@ -5,7 +5,7 @@ from datetime import datetime, timedelta, timezone
from psycopg2.extras import Json
from indian_paper_trading_strategy.engine.market import is_market_open, align_to_market_open
from indian_paper_trading_strategy.engine.market import is_market_open, align_to_market_open, market_now
from indian_paper_trading_strategy.engine.execution import try_execute_sip
from indian_paper_trading_strategy.engine.broker import PaperBroker, LiveZerodhaBroker, BrokerAuthExpired
from indian_paper_trading_strategy.engine.mtm import log_mtm, should_log_mtm
@ -315,7 +315,7 @@ def _engine_loop(config, stop_event: threading.Event):
# Gate 2: time to SIP
last_run = _last_execution_anchor(state, mode)
is_first_run = last_run is None
now = datetime.now()
now = market_now()
debug_event(
"ENGINE_LOOP_TICK",
"engine loop tick",

View File

@ -2,6 +2,7 @@
from datetime import datetime, timezone
from indian_paper_trading_strategy.engine.db import db_connection, insert_engine_event, run_with_retry, get_context
from indian_paper_trading_strategy.engine.market import market_now
DEFAULT_STATE = {
"initial_cash": 0.0,
@ -31,7 +32,7 @@ def _default_state(mode: str | None):
return DEFAULT_STATE.copy()
def _local_tz():
return datetime.now().astimezone().tzinfo
return market_now().tzinfo
def _format_local_ts(value: datetime | None):
if value is None: