base version only KD indicator with jpm, ft yahoo as sources
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
from flask import Flask, render_template, jsonify
|
||||
from datetime import datetime, timedelta
|
||||
from engine import DataEngine
|
||||
import concurrent.futures
|
||||
from flask_caching import Cache
|
||||
import csv, os, logging
|
||||
|
||||
app = Flask(__name__)
|
||||
cache = Cache(app, config={'CACHE_TYPE': 'SimpleCache'})
|
||||
|
||||
import os
|
||||
import csv
|
||||
|
||||
def load_instruments_from_csv(file_path):
|
||||
instruments = []
|
||||
|
||||
# Standard static templates
|
||||
# For AGI, we use the ISIN-based Tearsheet URL
|
||||
TEMPLATES = {
|
||||
'jpm': "https://am.jpmorgan.com/FundsMarketingHandler/historicalData?cusip={cusip}&country=hk&role=per",
|
||||
'yahoo': "https://query1.finance.yahoo.com/v8/finance/chart/{cusip}?range=5y&interval=1d",
|
||||
'agi': "https://markets.ft.com/data/funds/tearsheet/historical?s={cusip}"
|
||||
}
|
||||
|
||||
try:
|
||||
abs_path = os.path.join(os.path.dirname(__file__), file_path)
|
||||
|
||||
if not os.path.exists(abs_path):
|
||||
print(f"Error: {file_path} not found.")
|
||||
return []
|
||||
|
||||
with open(abs_path, mode='r', encoding='utf-8-sig') as csvfile:
|
||||
reader = csv.DictReader(csvfile)
|
||||
# Standardize header names to lowercase
|
||||
reader.fieldnames = [name.strip().lower() for name in reader.fieldnames]
|
||||
|
||||
for row in reader:
|
||||
symbol = row.get('symbol', '').strip()
|
||||
cusip = row.get('cusip', '').strip()
|
||||
provider = row.get('provider', 'jpm').strip().lower()
|
||||
|
||||
if symbol and cusip:
|
||||
# Fetch correct template; default to JPM if provider is unknown
|
||||
template = TEMPLATES.get(provider, TEMPLATES['jpm'])
|
||||
url = template.format(cusip=cusip)
|
||||
|
||||
instruments.append({
|
||||
"symbol": symbol,
|
||||
"url": url,
|
||||
"provider": provider
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"CSV Loading Error: {e}")
|
||||
|
||||
return instruments
|
||||
|
||||
# Usage
|
||||
URL_CONFIG = load_instruments_from_csv('instruments.csv')
|
||||
|
||||
@cache.memoize(timeout=3600)
|
||||
def fetch_and_calculate(config):
|
||||
engine = DataEngine(config['symbol'], config['url'], config['provider'])
|
||||
df = engine.fetch_data()
|
||||
if df is not None:
|
||||
metrics = engine.calculate_table_metrics(df)
|
||||
if metrics:
|
||||
metrics['symbol'] = config['symbol']
|
||||
return metrics
|
||||
return None
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
||||
@app.route('/api/summary')
|
||||
def get_summary():
|
||||
results = []
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
|
||||
futures = [executor.submit(fetch_and_calculate, cfg) for cfg in URL_CONFIG]
|
||||
for f in concurrent.futures.as_completed(futures):
|
||||
if f.result(): results.append(f.result())
|
||||
results.sort(key=lambda x: x['symbol'])
|
||||
return jsonify(results)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True, host='0.0.0.0', port=5000)
|
||||
Reference in New Issue
Block a user