add debug message to output latest file
This commit is contained in:
121
backend/app.py
121
backend/app.py
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user