Refactor code for improved readability and consistency

- Cleaned up whitespace and formatting in various files including http.py, language.py, logger.py, safe_exec.py, and SQL migration scripts.
- Consolidated import statements and removed unnecessary blank lines.
- Updated logging configuration for better clarity.
- Enhanced the safe execution code with improved error handling and logging.
- Removed commented-out code and unnecessary variables in backfill_zero_trades.py and other scripts.
- Added a pyproject.toml for Ruff and Vulture configuration.
- Introduced requirements-dev.txt for development dependencies.
- Removed commented-out stock entries in init.sql for cleaner migration scripts.
This commit is contained in:
dienakdz
2026-04-09 14:30:51 +07:00
parent 103055b3df
commit 87f2845483
157 changed files with 19026 additions and 17773 deletions
+112 -188
View File
@@ -4,15 +4,15 @@ Interactive Brokers API Routes
Standalone API endpoints for US stock trading.
"""
from flask import Blueprint, request, jsonify
from flask import Blueprint, jsonify, request
from app.utils.logger import get_logger
from app.services.ibkr_trading import IBKRClient, IBKRConfig
from app.services.ibkr_trading.client import get_ibkr_client, reset_ibkr_client
from app.utils.logger import get_logger
logger = get_logger(__name__)
ibkr_bp = Blueprint('ibkr', __name__)
ibkr_bp = Blueprint("ibkr", __name__)
# Global client instance
_client: IBKRClient = None
@@ -28,32 +28,27 @@ def _get_client() -> IBKRClient:
# ==================== Connection Management ====================
@ibkr_bp.route('/status', methods=['GET'])
@ibkr_bp.route("/status", methods=["GET"])
def get_status():
"""
Get connection status.
GET /api/ibkr/status
"""
try:
client = _get_client()
return jsonify({
"success": True,
"data": client.get_connection_status()
})
return jsonify({"success": True, "data": client.get_connection_status()})
except Exception as e:
logger.error(f"Get status failed: {e}")
return jsonify({
"success": False,
"error": str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500
@ibkr_bp.route('/connect', methods=['POST'])
@ibkr_bp.route("/connect", methods=["POST"])
def connect():
"""
Connect to TWS / IB Gateway.
POST /api/ibkr/connect
Body: {
"host": "127.0.0.1", // Optional, default 127.0.0.1
@@ -64,172 +59,132 @@ def connect():
}
"""
global _client
try:
data = request.get_json() or {}
# Build config
config = IBKRConfig(
host=data.get('host', '127.0.0.1'),
port=int(data.get('port', 7497)),
client_id=int(data.get('clientId', 1)),
account=data.get('account', ''),
readonly=data.get('readonly', False),
host=data.get("host", "127.0.0.1"),
port=int(data.get("port", 7497)),
client_id=int(data.get("clientId", 1)),
account=data.get("account", ""),
readonly=data.get("readonly", False),
)
# Disconnect existing connection
if _client is not None and _client.connected:
_client.disconnect()
# Create new client and connect
_client = IBKRClient(config)
success = _client.connect()
if success:
return jsonify({
"success": True,
"message": "Connected successfully",
"data": _client.get_connection_status()
})
return jsonify(
{"success": True, "message": "Connected successfully", "data": _client.get_connection_status()}
)
else:
return jsonify({
"success": False,
"error": "Connection failed. Please check if TWS/Gateway is running."
}), 400
except ImportError as e:
return jsonify({
"success": False,
"error": "ib_insync not installed. Run: pip install ib_insync"
}), 500
return jsonify(
{"success": False, "error": "Connection failed. Please check if TWS/Gateway is running."}
), 400
except ImportError:
return jsonify({"success": False, "error": "ib_insync not installed. Run: pip install ib_insync"}), 500
except Exception as e:
logger.error(f"Connection failed: {e}")
return jsonify({
"success": False,
"error": str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500
@ibkr_bp.route('/disconnect', methods=['POST'])
@ibkr_bp.route("/disconnect", methods=["POST"])
def disconnect():
"""
Disconnect from IBKR.
POST /api/ibkr/disconnect
"""
global _client
try:
if _client is not None:
_client.disconnect()
_client = None
reset_ibkr_client()
return jsonify({
"success": True,
"message": "Disconnected"
})
return jsonify({"success": True, "message": "Disconnected"})
except Exception as e:
logger.error(f"Disconnect failed: {e}")
return jsonify({
"success": False,
"error": str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500
# ==================== Account Queries ====================
@ibkr_bp.route('/account', methods=['GET'])
@ibkr_bp.route("/account", methods=["GET"])
def get_account():
"""
Get account information.
GET /api/ibkr/account
"""
try:
client = _get_client()
if not client.connected:
return jsonify({
"success": False,
"error": "Not connected to IBKR"
}), 400
return jsonify({
"success": True,
"data": client.get_account_summary()
})
return jsonify({"success": False, "error": "Not connected to IBKR"}), 400
return jsonify({"success": True, "data": client.get_account_summary()})
except Exception as e:
logger.error(f"Get account info failed: {e}")
return jsonify({
"success": False,
"error": str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500
@ibkr_bp.route('/positions', methods=['GET'])
@ibkr_bp.route("/positions", methods=["GET"])
def get_positions():
"""
Get positions.
GET /api/ibkr/positions
"""
try:
client = _get_client()
if not client.connected:
return jsonify({
"success": False,
"error": "Not connected to IBKR"
}), 400
return jsonify({"success": False, "error": "Not connected to IBKR"}), 400
positions = client.get_positions()
return jsonify({
"success": True,
"data": positions
})
return jsonify({"success": True, "data": positions})
except Exception as e:
logger.error(f"Get positions failed: {e}")
return jsonify({
"success": False,
"error": str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500
@ibkr_bp.route('/orders', methods=['GET'])
@ibkr_bp.route("/orders", methods=["GET"])
def get_orders():
"""
Get open orders.
GET /api/ibkr/orders
"""
try:
client = _get_client()
if not client.connected:
return jsonify({
"success": False,
"error": "Not connected to IBKR"
}), 400
return jsonify({"success": False, "error": "Not connected to IBKR"}), 400
orders = client.get_open_orders()
return jsonify({
"success": True,
"data": orders
})
return jsonify({"success": True, "data": orders})
except Exception as e:
logger.error(f"Get orders failed: {e}")
return jsonify({
"success": False,
"error": str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500
# ==================== Trading ====================
@ibkr_bp.route('/order', methods=['POST'])
@ibkr_bp.route("/order", methods=["POST"])
def place_order():
"""
Place an order.
POST /api/ibkr/order
Body: {
"symbol": "AAPL", // Required, symbol code
@@ -243,140 +198,109 @@ def place_order():
try:
client = _get_client()
if not client.connected:
return jsonify({
"success": False,
"error": "Not connected to IBKR"
}), 400
return jsonify({"success": False, "error": "Not connected to IBKR"}), 400
data = request.get_json() or {}
# Validate parameters
symbol = data.get('symbol')
side = data.get('side')
quantity = data.get('quantity')
symbol = data.get("symbol")
side = data.get("side")
quantity = data.get("quantity")
if not symbol:
return jsonify({"success": False, "error": "Missing symbol"}), 400
if not side or side.lower() not in ('buy', 'sell'):
if not side or side.lower() not in ("buy", "sell"):
return jsonify({"success": False, "error": "side must be buy or sell"}), 400
if not quantity or float(quantity) <= 0:
return jsonify({"success": False, "error": "quantity must be > 0"}), 400
market_type = data.get('marketType', 'USStock')
order_type = data.get('orderType', 'market').lower()
market_type = data.get("marketType", "USStock")
order_type = data.get("orderType", "market").lower()
# Place order
if order_type == 'limit':
price = data.get('price')
if order_type == "limit":
price = data.get("price")
if not price or float(price) <= 0:
return jsonify({"success": False, "error": "Limit order requires price"}), 400
result = client.place_limit_order(
symbol=symbol,
side=side,
quantity=float(quantity),
price=float(price),
market_type=market_type
symbol=symbol, side=side, quantity=float(quantity), price=float(price), market_type=market_type
)
else:
result = client.place_market_order(
symbol=symbol,
side=side,
quantity=float(quantity),
market_type=market_type
symbol=symbol, side=side, quantity=float(quantity), market_type=market_type
)
if result.success:
return jsonify({
"success": True,
"message": result.message,
"data": {
"orderId": result.order_id,
"filled": result.filled,
"avgPrice": result.avg_price,
"status": result.status,
"raw": result.raw
return jsonify(
{
"success": True,
"message": result.message,
"data": {
"orderId": result.order_id,
"filled": result.filled,
"avgPrice": result.avg_price,
"status": result.status,
"raw": result.raw,
},
}
})
)
else:
return jsonify({
"success": False,
"error": result.message
}), 400
return jsonify({"success": False, "error": result.message}), 400
except Exception as e:
logger.error(f"Place order failed: {e}")
return jsonify({
"success": False,
"error": str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500
@ibkr_bp.route('/order/<int:order_id>', methods=['DELETE'])
@ibkr_bp.route("/order/<int:order_id>", methods=["DELETE"])
def cancel_order(order_id: int):
"""
Cancel an order.
DELETE /api/ibkr/order/<order_id>
"""
try:
client = _get_client()
if not client.connected:
return jsonify({
"success": False,
"error": "Not connected to IBKR"
}), 400
return jsonify({"success": False, "error": "Not connected to IBKR"}), 400
success = client.cancel_order(order_id)
if success:
return jsonify({
"success": True,
"message": f"Order {order_id} cancelled"
})
return jsonify({"success": True, "message": f"Order {order_id} cancelled"})
else:
return jsonify({
"success": False,
"error": f"Order {order_id} not found"
}), 404
return jsonify({"success": False, "error": f"Order {order_id} not found"}), 404
except Exception as e:
logger.error(f"Cancel order failed: {e}")
return jsonify({
"success": False,
"error": str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500
# ==================== Market Data ====================
@ibkr_bp.route('/quote', methods=['GET'])
@ibkr_bp.route("/quote", methods=["GET"])
def get_quote():
"""
Get real-time quote.
GET /api/ibkr/quote?symbol=AAPL&marketType=USStock
"""
try:
client = _get_client()
if not client.connected:
return jsonify({
"success": False,
"error": "Not connected to IBKR"
}), 400
symbol = request.args.get('symbol')
market_type = request.args.get('marketType', 'USStock')
return jsonify({"success": False, "error": "Not connected to IBKR"}), 400
symbol = request.args.get("symbol")
market_type = request.args.get("marketType", "USStock")
if not symbol:
return jsonify({"success": False, "error": "Missing symbol"}), 400
quote = client.get_quote(symbol, market_type)
return jsonify(quote)
except Exception as e:
logger.error(f"Get quote failed: {e}")
return jsonify({
"success": False,
"error": str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500