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
这个提交包含在:
152
score_multi_model.py
普通文件
152
score_multi_model.py
普通文件
@@ -0,0 +1,152 @@
|
||||
#!/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}")
|
||||
在新工单中引用
屏蔽一个用户