from flask import Flask, request, jsonify
from datetime import datetime, timedelta
import random
import time
import hashlib
import traceback
app = Flask(__name__)
def generate_trades(source=None, trade_date=None, count=5000):
sources = [
"Bloomberg_FIX_FX",
"Bloomberg_FIX_Equity",
"Reuters_FX",
"Manual_Entry",
"Internal_Trade_System"
]
symbols = ["EUR/USD", "GBP/USD", "USD/JPY", "AAPL", "GOOGL", "MSFT", "GOLD", "OIL"]
statuses = ["Executed", "Pending", "Cancelled", "Settled"]
trades = []
for i in range(1, count + 1): trade = {
"TradeId": f"T{i:05d}",
"Source": random.choice(sources) if not source else source,
"Symbol": random.choice(symbols),
"Quantity": random.randint(100, 10000),
"Price": round(random.uniform(1.0, 1500.0), 4),
"TradeDate": datetime.now().strftime("%Y-%m-%d"),
"ExecutionTime": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"Status": random.choice(statuses),
"Account": f"ACC{random.randint(1000, 9999)}",
"Currency": random.choice(["USD", "EUR", "GBP"]),
"Broker": random.choice(["Broker1", "Broker2", "Broker3"])
}
trades.append(trade)
return trades
@app.route('/trades', methods=['GET', 'POST'])
def trades():
if request.method == 'POST':
try:
body = request.get_json()
print(f"Received POST body: {body}")
where_clause = body.get('Where') or body.get('where', '')
select_clause = body.get('Select') or body.get('select', '*')
print(f"Where clause: {where_clause}")
print(f"Select clause: {select_clause}")
source_filter = None
if 'Source' in where_clause:
import re
match = re.search(r'Source\s*=\s*"([^"]+)"', where_clause)
if match:
source_filter = match.group(1)
print(f"Filtered by source: {source_filter}")
selected_fields = []
if select_clause and select_clause != '*':
selected_fields = [f.strip() for f in select_clause.split(',')]
print(f"Selected fields: {selected_fields}")
all_trades = []
field_mapping = {
'Source': 'Source',
'PlatformOrderId': 'OrderId',
'BloomberTicker': 'Ticker',
'SignedQuantity': 'Quantity',
'BuySell': 'Side',
'Price': 'Price'
}
for i in range(1, 11): trade = {
'Source': source_filter if source_filter else random.choice(["Bloomberg", "Reuters", "TradeWeb"]),
'OrderId': f"ORD{random.randint(100000, 999999)}",
'Ticker': random.choice(["AAPL", "GOOGL", "MSFT", "TSLA", "AMZN"]),
'Quantity': random.randint(-5000, 5000), 'Side': random.choice(["Buy", "Sell"]),
'Price': round(random.uniform(100.0, 500.0), 2),
'TradeDate': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
if selected_fields:
filtered_trade = {}
for field in selected_fields:
mapped_field = field_mapping.get(field, field)
if mapped_field in trade:
if field == 'PlatformOrderId':
filtered_trade[field] = trade['OrderId']
elif field == 'BloomberTicker':
filtered_trade[field] = trade['Ticker']
elif field == 'SignedQuantity':
filtered_trade[field] = trade['Quantity']
elif field == 'BuySell':
filtered_trade[field] = trade['Side']
else:
filtered_trade[field] = trade.get(mapped_field, '')
all_trades.append(filtered_trade)
else:
all_trades.append(trade)
if 'TradeDate' in where_clause:
print("Date filter detected but not applied in mock")
return jsonify({"Result": all_trades})
except Exception as e:
print(f"Error processing request: {e}")
import traceback
traceback.print_exc()
return jsonify({"error": str(e)}), 400
return jsonify({"Result": generate_trades()})
@app.route('/counterparty_trades', methods=['GET', 'POST'])
def counterparty_trades():
return jsonify({"Result": generate_trades()})
@app.route('/securities', methods=['GET', 'POST'])
def securities():
securities_data = [
{"Ticker": "AAPL", "SecurityName": "Apple Inc.", "Sector": "Technology", "Currency": "USD", "Exchange": "NASDAQ", "ISIN": "US0378331005", "Multiplier": 1},
{"Ticker": "GOOGL", "SecurityName": "Alphabet Inc.", "Sector": "Technology", "Currency": "USD", "Exchange": "NASDAQ", "ISIN": "US02079K3059", "Multiplier": 1},
{"Ticker": "MSFT", "SecurityName": "Microsoft Corp.", "Sector": "Technology", "Currency": "USD", "Exchange": "NASDAQ", "ISIN": "US5949181045", "Multiplier": 1},
{"Ticker": "TSLA", "SecurityName": "Tesla Inc.", "Sector": "Automotive", "Currency": "USD", "Exchange": "NASDAQ", "ISIN": "US88160R1014", "Multiplier": 1},
{"Ticker": "AMZN", "SecurityName": "Amazon.com Inc.", "Sector": "Consumer Discretionary", "Currency": "USD", "Exchange": "NASDAQ", "ISIN": "US0231351067", "Multiplier": 1},
{"Ticker": "JPM", "SecurityName": "JPMorgan Chase", "Sector": "Financials", "Currency": "USD", "Exchange": "NYSE", "ISIN": "US46625H1005", "Multiplier": 1},
{"Ticker": "GS", "SecurityName": "Goldman Sachs", "Sector": "Financials", "Currency": "USD", "Exchange": "NYSE", "ISIN": "US38141G1040", "Multiplier": 1},
]
if request.method == 'POST':
body = request.get_json()
where_clause = body.get('Where', '').upper()
if 'TICKER' in where_clause:
import re
match = re.search(r'TICKER.*IN.*\((.*?)\)', where_clause)
if match:
tickers = [t.strip().strip('"').strip("'") for t in match.group(1).split(',')]
securities_data = [s for s in securities_data if s['Ticker'] in tickers]
return jsonify({"Result": securities_data})
@app.route('/fix_messages', methods=['GET', 'POST'])
def fix_messages():
base_time = datetime.now()
fix_data = []
for i in range(20):
send_time = base_time + timedelta(seconds=i*2 + random.uniform(-0.5, 0.5))
exec_time = send_time + timedelta(milliseconds=random.randint(50, 500))
msg = {
"MsgSeqNum": i + 1,
"MsgType": "8", "ExecType": random.choice(["0", "1", "2"]), "OrdStatus": random.choice(["0", "1", "2"]), "ClOrdID": f"CLO{i+1:05d}", "OrderID": f"ORD{random.randint(100000, 999999)}", "Symbol": random.choice(["AAPL", "GOOGL", "MSFT", "TSLA", "AMZN"]), "Side": random.choice(["1", "2"]), "OrderQty": random.randint(100, 5000), "LastQty": random.randint(100, 1000), "LastPx": round(random.uniform(100.0, 500.0), 2), "SendingTime": send_time.strftime("%Y%m%d-%H:%M:%S.%f")[:-3], "TransactTime": exec_time.strftime("%Y%m%d-%H:%M:%S.%f")[:-3], "AllocAccount": f"ACC{random.randint(1000, 9999)}", "LatencyMs": int((exec_time - send_time).total_seconds() * 1000)
}
fix_data.append(msg)
if request.method == 'POST':
body = request.get_json()
tags = body.get('tags', [])
if tags:
tag_map = {
"35": "MsgType", "8": "MsgSeqNum", "79": "AllocAccount",
"52": "SendingTime", "60": "TransactTime", "11": "ClOrdID",
"37": "OrderID", "55": "Symbol", "54": "Side",
"38": "OrderQty", "31": "LastPx", "32": "LastQty"
}
filtered_data = []
for msg in fix_data:
filtered_msg = {}
for tag in tags:
field_name = tag_map.get(tag, tag)
if field_name in msg:
filtered_msg[field_name] = msg[field_name]
filtered_msg["LatencyMs"] = msg["LatencyMs"]
filtered_data.append(filtered_msg)
fix_data = filtered_data
return jsonify({"Result": fix_data})
@app.route('/parent_orders', methods=['GET', 'POST'])
def parent_orders():
parent_orders = []
for parent_id in range(1, 6):
parent_ticker = random.choice(["AAPL", "GOOGL", "MSFT"])
parent_qty = random.randint(5000, 20000)
child_count = random.randint(5, 15)
base_price = random.uniform(100.0, 500.0)
base_time = datetime.now() - timedelta(hours=2) + timedelta(minutes=parent_id*10)
parent = {
"ParentOrderID": f"PARENT{parent_id:03d}",
"Ticker": parent_ticker,
"TotalQuantity": parent_qty,
"Side": random.choice(["Buy", "Sell"]),
"OrderTime": base_time.strftime("%Y-%m-%d %H:%M:%S"),
"Status": "Completed",
"ChildExecutions": []
}
remaining_qty = parent_qty
for child_id in range(child_count):
child_qty = min(remaining_qty, random.randint(100, 1000))
remaining_qty -= child_qty
child_price = base_price + random.uniform(-5.0, 5.0)
child_time = base_time + timedelta(seconds=child_id*30 + random.randint(0, 20))
child = {
"ChildOrderID": f"CHILD{parent_id:03d}_{child_id+1:02d}",
"ParentOrderID": f"PARENT{parent_id:03d}",
"Ticker": parent_ticker,
"Quantity": child_qty,
"Price": round(child_price, 2),
"ExecutionTime": child_time.strftime("%Y-%m-%d %H:%M:%S"),
"Venue": random.choice(["NASDAQ", "NYSE", "ARCA", "BATS"])
}
parent["ChildExecutions"].append(child)
parent_orders.append(child)
if remaining_qty <= 0:
break
return jsonify({"Result": parent_orders})
@app.route('/token', methods=['GET'])
def get_token():
timestamp = str(int(time.time()))
expires = int(time.time()) + 900
token_data = f"test-token-{timestamp}-{expires}"
token_hash = hashlib.sha256(token_data.encode()).hexdigest()[:32]
token = f"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.{token_hash}.{timestamp}"
return jsonify({
"token": token,
"expires_in": 900,
"expires_at": datetime.fromtimestamp(expires).isoformat(),
"type": "Bearer"
})
@app.route('/health', methods=['GET'])
def health():
return jsonify({"status": "healthy", "timestamp": datetime.now().isoformat()})
@app.route('/protected/data', methods=['GET'])
def protected_data():
auth_header = request.headers.get('Authorization')
if not auth_header or not auth_header.startswith('Bearer '):
return jsonify({"error": "Unauthorized"}), 401
token = auth_header.replace('Bearer ', '')
print(f"Received token: {token}")
return jsonify({
"Result": generate_trades(),
"authenticated": True,
"token_received": token[:10] + "..." if len(token) > 10 else token
})
if __name__ == '__main__':
print("""
╔════════════════════════════════════════════════════════════════╗
║ Test Trade Server for SQL-CLI Temp Tables Demo ║
╠════════════════════════════════════════════════════════════════╣
║ Running on: http://localhost:5001 ║
║ ║
║ Endpoints: ║
║ GET /token - Test JWT token (15 min expiry) ║
║ POST /trades - Trade data (select/where body) ║
║ GET /trades - All trades ║
║ POST /counterparty_trades - Counterparty trades ║
║ POST /securities - Securities master data ║
║ POST /fix_messages - FIX protocol messages ║
║ POST /parent_orders - Parent/child order executions ║
║ GET /health - Health check ║
║ GET /protected/data - Requires Bearer token ║
║ ║
║ Test Examples: ║
║ examples/cte_flask_dependency.sql - Multi-stage analysis ║
║ ║
║ Usage: ║
║ sql-cli -f examples/cte_flask_dependency.sql ║
║ sql-cli -f examples/cte_flask_dependency.sql --execute-statement 4 ║
║ ║
║ In Neovim: \\sq (all) or \\sx (statement at cursor) ║
╚════════════════════════════════════════════════════════════════╝
""")
app.run(host='0.0.0.0', port=5001, debug=True)