add debug message to output latest file

This commit is contained in:
2026-04-06 10:21:21 -05:00
parent 21f5247e38
commit 15c00b92ba

View File

@@ -1,12 +1,12 @@
"""Flask backend for IB dashboard. """Flask backend for IB dashboard.
Provides simple REST endpoints that the vanilla-JS frontend polls: Provides simple REST endpoints that the vanilla-JS frontend polls:
- GET /api/quotes -> latest market quotes - GET /api/quotes -> latest market quotes
- GET /api/positions -> latest positions - GET /api/positions -> latest positions
- POST /api/subscribe { symbols: ["AAPL","MSFT"] } -> start subscribing - POST /api/subscribe { symbols: ["AAPL","MSFT"] } -> start subscribing
This app expects an IB Gateway or TWS running locally on port 7496. This app expects an IB Gateway or TWS running locally on port 7496.
""" """
from flask import Flask, jsonify, request, send_from_directory from flask import Flask, jsonify, request, send_from_directory
import os import os
import threading import threading
@@ -132,49 +132,54 @@ def start_flex_startup_sync_if_needed() -> None:
# instantiate the IB client with a process-unique client id to avoid # instantiate the IB client with a process-unique client id to avoid
# collisions when Flask's reloader spawns multiple processes. # collisions when Flask's reloader spawns multiple processes.
ib = IBClient(client_id=os.getpid()) ib = IBClient(client_id=os.getpid())
# Start connection only in the main process (Werkzeug sets WERKZEUG_RUN_MAIN) # Start connection only in the main process (Werkzeug sets WERKZEUG_RUN_MAIN)
if os.environ.get("WERKZEUG_RUN_MAIN") == "true" or not os.environ.get("WERKZEUG_RUN_MAIN"): if os.environ.get("WERKZEUG_RUN_MAIN") == "true" or not os.environ.get("WERKZEUG_RUN_MAIN"):
# attempt to start the connection; failures are logged by the client # attempt to start the connection; failures are logged by the client
try: try:
ib.connect_and_start() ib.connect_and_start()
except Exception: except Exception:
pass pass
start_flex_startup_sync_if_needed() start_flex_startup_sync_if_needed()
@app.route("/") @app.route("/")
def index(): def index():
return send_from_directory(app.static_folder, "index.html") return send_from_directory(app.static_folder, "index.html")
@app.route("/api/quotes") @app.route("/api/quotes")
def api_quotes(): def api_quotes():
return jsonify(ib.get_quotes()) return jsonify(ib.get_quotes())
@app.route("/api/positions") @app.route("/api/positions")
def api_positions(): def api_positions():
# request a fresh positions snapshot from IB and wait briefly for callbacks # request a fresh positions snapshot from IB and wait briefly for callbacks
try: try:
ib.request_positions() ib.request_positions()
except Exception: except Exception:
pass pass
# wait up to 2 seconds for positions to arrive # wait up to 2 seconds for positions to arrive
deadline = time.time() + 2.0 deadline = time.time() + 2.0
while time.time() < deadline: while time.time() < deadline:
positions = ib.get_positions() positions = ib.get_positions()
if positions: if positions:
return jsonify(positions) return jsonify(positions)
time.sleep(0.1) time.sleep(0.1)
# return whatever we have (possibly empty) # return whatever we have (possibly empty)
return jsonify(ib.get_positions()) return jsonify(ib.get_positions())
@app.route("/api/lots") @app.route("/api/lots")
def api_lots(): def api_lots():
api_flex_sync()
flex_status = get_flex_status() flex_status = get_flex_status()
if flex_status.get("configured") and flex_status.get("data_dir"): if flex_status.get("configured") and flex_status.get("data_dir"):
latest_file, flex_lots = load_latest_flex_lots(flex_status["data_dir"]) latest_file, flex_lots = load_latest_flex_lots(flex_status["data_dir"])
print(
f"[D]Latest file{latest_file} "
)
if latest_file and flex_lots: if latest_file and flex_lots:
return jsonify(flex_lots) return jsonify(flex_lots)
@@ -341,19 +346,19 @@ def api_flex_sync():
_flex_sync_state["last_result"] = "error" _flex_sync_state["last_result"] = "error"
_flex_sync_state["last_error"] = str(exc) _flex_sync_state["last_error"] = str(exc)
return jsonify({"ok": False, "error": str(exc)}), 500 return jsonify({"ok": False, "error": str(exc)}), 500
@app.route("/api/subscribe", methods=["POST"]) @app.route("/api/subscribe", methods=["POST"])
def api_subscribe(): def api_subscribe():
data = request.get_json(force=True) data = request.get_json(force=True)
symbols = data.get("symbols", []) if isinstance(data, dict) else [] symbols = data.get("symbols", []) if isinstance(data, dict) else []
if not isinstance(symbols, list): if not isinstance(symbols, list):
return jsonify({"error": "symbols must be a list"}), 400 return jsonify({"error": "symbols must be a list"}), 400
for s in symbols: for s in symbols:
ib.subscribe_market_data(s) ib.subscribe_market_data(s)
return jsonify({"subscribed": symbols}) return jsonify({"subscribed": symbols})
if __name__ == "__main__": if __name__ == "__main__":
# simple dev server; disable reloader to avoid duplicate IB client instances # simple dev server; disable reloader to avoid duplicate IB client instances
app.run(debug=True, port=8000, use_reloader=False) app.run(debug=True, port=8000, use_reloader=False)