文件
memely-alpha-stock-ranking/score_multi_model.py
hao 90d58a000b Add multi-model scoring: GPT-4.1-mini, GPT-4.1-nano, Gemini-2.5-flash
- MemelyAlphaStockRanking_multi_model.xlsx: 13-sheet Excel with per-model scores
  - Multi-Model Comparison (cross-model ranking)
  - Model Legend (color coding guide)
  - Scores - GPT-4.1-mini (blue highlights)
  - Scores - GPT-4.1-nano (green highlights)
  - Scores - Gemini-2.5-flash (purple highlights)
  - Rank sheets for each model
- scores_gpt41nano.json: GPT-4.1-nano raw scores
- scores_gemini25flash.json: Gemini-2.5-flash raw scores
- score_multi_model.py: Multi-model scoring script
- build_multi_model_excel.py: Excel generation script
2026-03-14 08:01:52 -04:00

153 行
5.3 KiB
Python

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
#!/usr/bin/env python3
"""
Score all stocks using a specified AI model.
Usage: python3 score_multi_model.py <model_name> <output_json>
"""
import pandas as pd
import json
import os
import sys
import time
from openai import OpenAI
model_name = sys.argv[1]
output_json = sys.argv[2]
client = OpenAI()
EXCEL_PATH = "/home/ubuntu/upload/MemelyAlphaStockRanking副本副本.xlsx"
# Read the master list
df = pd.read_excel(EXCEL_PATH, sheet_name='stock master list')
df4 = pd.read_excel(EXCEL_PATH, sheet_name='Sheet4')
sector_map = {}
for _, row in df4.iterrows():
sym = row.get('Symbol')
if pd.notna(sym):
sector_map[sym] = {
'sector': row.get('Sector', ''),
'theme': row.get('Theme', ''),
}
# Build stock info
stocks_info = []
seen = set()
for _, row in df.iterrows():
sym = row['Symbol']
if pd.isna(sym) or sym in seen:
continue
seen.add(sym)
info = {
'symbol': sym,
'theme': str(row.get('Theme', '')),
'perf_7d': row.get('performance past 7 days', None),
'perf_ytd': row.get('performance Year to Date', None),
'perf_specific': row.get('performance on specific dates', None),
'first_call_kol': str(row.get('first call X kol', '')),
'top_contributor': str(row.get('top contributor', '')),
}
if sym in sector_map:
info['sector'] = sector_map[sym].get('sector', '')
info['theme_s4'] = sector_map[sym].get('theme', '')
stocks_info.append(info)
print(f"[{model_name}] Total stocks to score: {len(stocks_info)}")
def score_batch(batch_stocks, model):
stocks_text = ""
for s in batch_stocks:
perf_7d = f"{s['perf_7d']:.2%}" if pd.notna(s.get('perf_7d')) else "N/A"
perf_ytd = f"{s['perf_ytd']:.2%}" if pd.notna(s.get('perf_ytd')) else "N/A"
perf_spec = f"{s['perf_specific']:.2%}" if pd.notna(s.get('perf_specific')) else "N/A"
sector = s.get('sector', s.get('theme', 'N/A'))
theme = s.get('theme_s4', s.get('theme', 'N/A'))
stocks_text += f"""
---
Symbol: {s['symbol']}
Sector: {sector}
Theme: {theme}
Performance (Past 7 Days): {perf_7d}
Performance (Year to Date): {perf_ytd}
Performance (Specific Date): {perf_spec}
First Call KOL: {s.get('first_call_kol', 'N/A')}
Top Contributor: {s.get('top_contributor', 'N/A')}
"""
prompt = f"""You are a professional stock/crypto analyst. Evaluate each of the following stocks/assets and provide a comprehensive score.
For EACH stock, provide:
1. **overall_score** (1-100): Overall investment attractiveness score
2. **momentum_score** (1-100): Based on recent price performance and momentum
3. **theme_score** (1-100): How strong/relevant is the thematic play (e.g., AI, Defense, Aerospace, Crypto, etc.)
4. **risk_score** (1-100): Risk level (100 = highest risk)
5. **social_buzz_score** (1-100): Social media attention and KOL backing strength
6. **brief_analysis**: 2-3 sentence analysis explaining the scores
Consider these factors:
- YTD performance indicates momentum strength
- Thematic relevance to current market trends (AI, Defense, Aerospace, Crypto, Quantum Computing are hot in 2025-2026)
- Small/micro cap stocks with strong themes get higher theme scores
- Stocks with notable KOL backing get higher social buzz scores
- Higher volatility = higher risk score
Here are the stocks to evaluate:
{stocks_text}
Return ONLY a valid JSON array with objects for each stock. Each object must have: symbol, overall_score, momentum_score, theme_score, risk_score, social_buzz_score, brief_analysis.
Do not include any text outside the JSON array."""
for attempt in range(3):
try:
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": "You are a professional financial analyst. Always respond with valid JSON only."},
{"role": "user", "content": prompt}
],
temperature=0.3,
max_tokens=8000
)
content = response.choices[0].message.content.strip()
if content.startswith("```"):
content = content.split("```")[1]
if content.startswith("json"):
content = content[4:]
results = json.loads(content)
return results
except Exception as e:
print(f" Attempt {attempt+1} error: {e}")
time.sleep(3)
return None
# Process in batches
batch_size = 15
scored = {}
total_batches = (len(stocks_info) + batch_size - 1) // batch_size
for i in range(0, len(stocks_info), batch_size):
batch = stocks_info[i:i+batch_size]
batch_num = i // batch_size + 1
symbols_in_batch = [s['symbol'] for s in batch]
print(f"[{model_name}] Batch {batch_num}/{total_batches}: {symbols_in_batch}")
results = score_batch(batch, model_name)
if results:
for r in results:
sym = r.get('symbol', '')
if sym:
scored[sym] = r
print(f"{sym}: Overall={r.get('overall_score')}")
else:
print(f" ✗ Batch {batch_num} failed after retries")
time.sleep(1)
with open(output_json, 'w') as f:
json.dump(scored, f, indent=2, ensure_ascii=False)
print(f"\n[{model_name}] COMPLETE: {len(scored)}/{len(stocks_info)} scored")
print(f"Saved to: {output_json}")