Fix timezone handling and countdown messages
This commit is contained in:
1 parent
9059843460
commit
45945da125
1 file changed
+34
-16
+34
-16
@@ -12,6 +12,7 @@ import json
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
import pytz
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
import alpaca_trade_api as tradeapi
|
import alpaca_trade_api as tradeapi
|
||||||
@@ -128,6 +129,8 @@ REQUIRE_MACD_CONFIRMATION = bool(config["REQUIRE_MACD_CONFIRMATION"])
|
|||||||
MIN_RISK_REWARD = float(config["MIN_RISK_REWARD"])
|
MIN_RISK_REWARD = float(config["MIN_RISK_REWARD"])
|
||||||
PULLBACK_PERCENTAGE = float(config["PULLBACK_PERCENTAGE"])
|
PULLBACK_PERCENTAGE = float(config["PULLBACK_PERCENTAGE"])
|
||||||
|
|
||||||
|
EASTERN = pytz.timezone('US/Eastern')
|
||||||
|
|
||||||
api = tradeapi.REST(
|
api = tradeapi.REST(
|
||||||
os.getenv('APCA_API_KEY_ID'),
|
os.getenv('APCA_API_KEY_ID'),
|
||||||
os.getenv('APCA_API_SECRET_KEY'),
|
os.getenv('APCA_API_SECRET_KEY'),
|
||||||
@@ -493,7 +496,7 @@ def should_skip_trading_day():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
today = datetime.now().weekday()
|
today = datetime.now().weekday()
|
||||||
day_name = datetime.now().strftime("%A")
|
day_name = datetime.now(EASTERN).strftime("%A")
|
||||||
if today == 0 or today == 4:
|
if today == 0 or today == 4:
|
||||||
debug_print(f"Skipping {day_name} (skip_mondays_fridays enabled)")
|
debug_print(f"Skipping {day_name} (skip_mondays_fridays enabled)")
|
||||||
return True
|
return True
|
||||||
@@ -520,9 +523,15 @@ def seconds_to_human_readable(seconds):
|
|||||||
return " ".join(time_parts) if time_parts else "0 seconds"
|
return " ".join(time_parts) if time_parts else "0 seconds"
|
||||||
|
|
||||||
def format_market_time(dt_obj):
|
def format_market_time(dt_obj):
|
||||||
eastern_time = dt_obj.strftime("%Y-%m-%d %I:%M:%S %p %Z")
|
|
||||||
if hasattr(dt_obj, 'to_pydatetime'):
|
if hasattr(dt_obj, 'to_pydatetime'):
|
||||||
dt_obj = dt_obj.to_pydatetime()
|
dt_obj = dt_obj.to_pydatetime()
|
||||||
|
|
||||||
|
if dt_obj.tzinfo is None:
|
||||||
|
dt_obj = EASTERN.localize(dt_obj)
|
||||||
|
elif dt_obj.tzinfo != EASTERN:
|
||||||
|
dt_obj = dt_obj.astimezone(EASTERN)
|
||||||
|
|
||||||
|
eastern_time = dt_obj.strftime("%Y-%m-%d %I:%M:%S %p %Z")
|
||||||
local_time = dt_obj.astimezone().strftime("%I:%M%p").lstrip('0')
|
local_time = dt_obj.astimezone().strftime("%I:%M%p").lstrip('0')
|
||||||
return f"{eastern_time} ({local_time} local)"
|
return f"{eastern_time} ({local_time} local)"
|
||||||
|
|
||||||
@@ -1020,11 +1029,21 @@ def wait_until_market_open():
|
|||||||
return
|
return
|
||||||
|
|
||||||
now = clock.timestamp
|
now = clock.timestamp
|
||||||
|
if now.tzinfo is None:
|
||||||
|
now = EASTERN.localize(now)
|
||||||
|
else:
|
||||||
|
now = now.astimezone(EASTERN)
|
||||||
|
|
||||||
next_open = clock.next_open
|
next_open = clock.next_open
|
||||||
|
if next_open.tzinfo is None:
|
||||||
|
next_open = EASTERN.localize(next_open)
|
||||||
|
else:
|
||||||
|
next_open = next_open.astimezone(EASTERN)
|
||||||
|
|
||||||
if not clock.is_open:
|
if not clock.is_open:
|
||||||
seconds_until_open = (next_open - now).total_seconds()
|
seconds_until_open = (next_open - now).total_seconds()
|
||||||
debug_print(f"Market closed, {seconds_until_open:.0f} seconds until open")
|
readable_time = seconds_to_human_readable(seconds_until_open)
|
||||||
|
debug_print(f"Market closed, {readable_time} until open")
|
||||||
if seconds_until_open > 0:
|
if seconds_until_open > 0:
|
||||||
readable_time = seconds_to_human_readable(seconds_until_open)
|
readable_time = seconds_to_human_readable(seconds_until_open)
|
||||||
logger.info(f"🕒 Market opens at {format_market_time(next_open)}")
|
logger.info(f"🕒 Market opens at {format_market_time(next_open)}")
|
||||||
@@ -1035,7 +1054,7 @@ def wait_until_market_open():
|
|||||||
time.sleep(sleep_time)
|
time.sleep(sleep_time)
|
||||||
seconds_until_open -= sleep_time
|
seconds_until_open -= sleep_time
|
||||||
|
|
||||||
if sleep_time >= 60:
|
if sleep_time >= 60 and (seconds_until_open % 3600 < 60 or seconds_until_open < 3600):
|
||||||
remaining_readable = seconds_to_human_readable(seconds_until_open)
|
remaining_readable = seconds_to_human_readable(seconds_until_open)
|
||||||
logger.info(f"⏱️ {remaining_readable} remaining...")
|
logger.info(f"⏱️ {remaining_readable} remaining...")
|
||||||
debug_print(f"Waiting... {remaining_readable} remaining")
|
debug_print(f"Waiting... {remaining_readable} remaining")
|
||||||
@@ -1368,19 +1387,19 @@ def should_trade_based_on_market_hours():
|
|||||||
debug_print("Market hours filter disabled")
|
debug_print("Market hours filter disabled")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
now = datetime.now().time()
|
now_eastern = datetime.now(EASTERN).time()
|
||||||
|
|
||||||
open_buffer_end = datetime.strptime("10:00", "%H:%M").time()
|
open_buffer_end = datetime.strptime("10:00", "%H:%M").time()
|
||||||
close_buffer_start = datetime.strptime("15:30", "%H:%M").time()
|
close_buffer_start = datetime.strptime("15:30", "%H:%M").time()
|
||||||
|
|
||||||
debug_print(f"Current time: {now}")
|
debug_print(f"Current time (ET): {now_eastern}")
|
||||||
|
|
||||||
if now < open_buffer_end:
|
if now_eastern < open_buffer_end:
|
||||||
debug_print("Before 10:00 AM, outside trading hours")
|
debug_print("Before 10:00 AM ET, outside trading hours")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if now >= close_buffer_start:
|
if now_eastern >= close_buffer_start:
|
||||||
debug_print("After 3:30 PM, outside trading hours")
|
debug_print("After 3:30 PM ET, outside trading hours")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
debug_print("Within trading hours")
|
debug_print("Within trading hours")
|
||||||
@@ -1593,7 +1612,7 @@ def main():
|
|||||||
while True:
|
while True:
|
||||||
debug_print("=== NEW MAIN LOOP ITERATION ===")
|
debug_print("=== NEW MAIN LOOP ITERATION ===")
|
||||||
try:
|
try:
|
||||||
current_date = datetime.now().date()
|
current_date = datetime.now(EASTERN).date()
|
||||||
if last_reset_date != current_date:
|
if last_reset_date != current_date:
|
||||||
trades_today = 0
|
trades_today = 0
|
||||||
last_reset_date = current_date
|
last_reset_date = current_date
|
||||||
@@ -1608,7 +1627,7 @@ def main():
|
|||||||
debug_print("Reset trailing_stop attribute")
|
debug_print("Reset trailing_stop attribute")
|
||||||
|
|
||||||
if should_skip_trading_day():
|
if should_skip_trading_day():
|
||||||
day_name = datetime.now().strftime("%A")
|
day_name = datetime.now(EASTERN).strftime("%A")
|
||||||
logger.info(f"📅 Skipping {day_name} - monitoring mode")
|
logger.info(f"📅 Skipping {day_name} - monitoring mode")
|
||||||
debug_print(f"Skipping trading today ({day_name})")
|
debug_print(f"Skipping trading today ({day_name})")
|
||||||
time.sleep(3600)
|
time.sleep(3600)
|
||||||
@@ -1668,7 +1687,7 @@ def main():
|
|||||||
time.sleep(60)
|
time.sleep(60)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if datetime.now().date() != current_date:
|
if datetime.now(EASTERN).date() != current_date:
|
||||||
logger.info("📅 Day changed - resetting")
|
logger.info("📅 Day changed - resetting")
|
||||||
debug_print("Day changed, exiting session loop")
|
debug_print("Day changed, exiting session loop")
|
||||||
break
|
break
|
||||||
@@ -1703,7 +1722,7 @@ def main():
|
|||||||
debug_print(f"Managing active position: type={position_type}, entry=${entry_price:.2f}")
|
debug_print(f"Managing active position: type={position_type}, entry=${entry_price:.2f}")
|
||||||
|
|
||||||
if entry_time:
|
if entry_time:
|
||||||
time_in_trade = (datetime.now() - entry_time).total_seconds()
|
time_in_trade = (datetime.now(EASTERN) - entry_time).total_seconds()
|
||||||
debug_print(f"Time in trade: {time_in_trade:.0f}s (max: {MAX_HOLD_TIME}s)")
|
debug_print(f"Time in trade: {time_in_trade:.0f}s (max: {MAX_HOLD_TIME}s)")
|
||||||
if time_in_trade > MAX_HOLD_TIME:
|
if time_in_trade > MAX_HOLD_TIME:
|
||||||
logger.info(f"⏰ Max hold time ({MAX_HOLD_TIME//60} min)")
|
logger.info(f"⏰ Max hold time ({MAX_HOLD_TIME//60} min)")
|
||||||
@@ -1785,13 +1804,12 @@ def main():
|
|||||||
trade_count += 1
|
trade_count += 1
|
||||||
trades_today += 1
|
trades_today += 1
|
||||||
entry_price = execution_price
|
entry_price = execution_price
|
||||||
entry_time = datetime.now()
|
entry_time = datetime.now(EASTERN)
|
||||||
stop_loss = signal_stop_loss
|
stop_loss = signal_stop_loss
|
||||||
position_active = True
|
position_active = True
|
||||||
position_type = 'long' if signal == 'buy' else 'short'
|
position_type = 'long' if signal == 'buy' else 'short'
|
||||||
|
|
||||||
risk_amount = abs(entry_price - stop_loss) / entry_price
|
risk_amount = abs(entry_price - stop_loss) / entry_price
|
||||||
logger.info(f"✅ {signal.upper()} executed")
|
|
||||||
logger.info(f" Entry=${entry_price:.2f}, Stop=${stop_loss:.2f}, Risk={risk_amount:.2%}")
|
logger.info(f" Entry=${entry_price:.2f}, Stop=${stop_loss:.2f}, Risk={risk_amount:.2%}")
|
||||||
logger.info(f" Regime={regime}, Strength={strength:.2f}, Trade #{trade_count} ({trades_today}/{MAX_TRADES_PER_DAY})")
|
logger.info(f" Regime={regime}, Strength={strength:.2f}, Trade #{trade_count} ({trades_today}/{MAX_TRADES_PER_DAY})")
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user