This commit is contained in:
jack
2025-11-25 09:45:49 +08:00
parent ad98c97949
commit 41ef816a81
34 changed files with 1518 additions and 1 deletions
+56
View File
@@ -0,0 +1,56 @@
[
{
"name": "做空股价潜力有限",
"expression": "-rank(ebit / capex)",
"settings": {
"instrumentType": "EQUITY",
"region": "USA",
"universe": "TOP3000",
"delay": 1,
"decay": 0,
"neutralization": "INDUSTRY",
"truncation": 0.08,
"pasteurization": "ON",
"unitHandling": "VERIFY",
"nanHandling": "OFF",
"language": "FASTEXPR",
"visualization": false
}
},
{
"name": "财务健康度标准化",
"expression": "zscore(cash_st / debt_st)",
"settings": {
"instrumentType": "EQUITY",
"region": "USA",
"universe": "TOP3000",
"delay": 1,
"decay": 0,
"neutralization": "INDUSTRY",
"truncation": 0.1,
"pasteurization": "ON",
"unitHandling": "VERIFY",
"nanHandling": "OFF",
"language": "FASTEXPR",
"visualization": false
}
},
{
"name": "做空12个月社交媒体讨论热度高",
"expression": "-scl12_buzz",
"settings": {
"instrumentType": "EQUITY",
"region": "USA",
"universe": "TOP3000",
"delay": 1,
"decay": 0,
"neutralization": "INDUSTRY",
"truncation": 0.12,
"pasteurization": "ON",
"unitHandling": "VERIFY",
"nanHandling": "OFF",
"language": "FASTEXPR",
"visualization": false
}
}
]
+1
View File
@@ -0,0 +1 @@
['jack0210_@hotmail.com', '!QAZ2wsx+0913']
+247
View File
@@ -0,0 +1,247 @@
import httpx
import json
from concurrent.futures import ThreadPoolExecutor, as_completed
from os.path import expanduser, exists
from httpx import BasicAuth
from time import sleep
from datetime import datetime
class WorldQuantBrainAPI:
def __init__(self, credentials_file='brain_credentials.txt'):
"""初始化API客户端"""
self.credentials_file = expanduser(credentials_file)
self.client = None
self.brain_api_url = 'https://api.worldquantbrain.com'
def login(self):
"""登录认证"""
try:
# 检查凭证文件是否存在
if not exists(self.credentials_file):
print(f"❌ 凭证文件不存在: {self.credentials_file}")
return False
# Load credentials
with open(self.credentials_file) as f:
file_content = f.read().strip()
with open(self.credentials_file) as f:
credentials = eval(f.read())
# Extract username and password from the list
if len(credentials) != 2:
print(f"❌ 凭证格式错误,应该是 [username, password] 格式,但得到: {credentials}")
return False
username, password = credentials
# Create a client with basic authentication
self.client = httpx.Client(auth=BasicAuth(username, password))
# Send authentication request
response = self.client.post(f'{self.brain_api_url}/authentication')
print(f"认证状态: {response.status_code}")
if response.status_code == 201:
print("✅ 登录成功!")
return True
else:
print(f"❌ 登录失败: {response.text}")
return False
except json.JSONDecodeError as e:
print(f"❌ JSON解析错误: {e}")
print(f"📄 文件内容: {file_content if 'file_content' in locals() else '无法读取'}")
return False
except Exception as e:
print(f"❌ 登录过程中出错: {str(e)}")
return False
def batch_simulate_alphas(self, alphas_config_file='alphas.json', max_workers=3):
"""批量测试多个Alpha因子(使用线程池)"""
# 检查配置文件是否存在
if not exists(alphas_config_file):
print(f"❌ 配置文件 {alphas_config_file} 不存在")
return []
# 读取Alpha配置
try:
with open(alphas_config_file, 'r', encoding='utf-8') as f:
file_content = f.read().strip()
print(f"📄 Alpha配置文件内容预览: {file_content[:200]}...") # 只显示前200个字符
with open(alphas_config_file, 'r', encoding='utf-8') as f:
alpha_configs = json.load(f)
print(f"✅ 成功读取 {len(alpha_configs)} 个Alpha配置")
for i, config in enumerate(alpha_configs):
print(f" {i+1}. {config.get('name', '未命名')}")
except json.JSONDecodeError as e:
print(f"❌ 配置文件 JSON格式错误: {e}")
print(f"📄 出错的文件内容: {file_content if 'file_content' in locals() else '无法读取'}")
return []
except Exception as e:
print(f"❌ 读取配置文件时出错: {str(e)}")
return []
print(f"📁 读取到 {len(alpha_configs)} 个Alpha配置")
# 登录
if not self.login():
print("❌ 登录失败,无法继续")
return []
results = []
# 使用线程池并发执行
with ThreadPoolExecutor(max_workers=max_workers) as executor:
# 提交所有任务
future_to_alpha = {
executor.submit(self.simulate_alpha, config): config
for config in alpha_configs
}
# 收集结果
for future in as_completed(future_to_alpha):
config = future_to_alpha[future]
try:
result = future.result()
results.append(result)
except Exception as e:
print(f"❌ {config.get('name', '未知Alpha')} 执行失败: {str(e)}")
results.append({
'name': config.get('name', '未知Alpha'),
'success': False,
'error': str(e)
})
# 打印汇总结果
self._print_summary(results)
return results
def simulate_alpha(self, alpha_config):
"""模拟单个Alpha因子"""
if self.client is None:
raise Exception("请先调用 login() 方法登录")
name = alpha_config.get('name', '未命名Alpha')
expression = alpha_config['expression']
settings = alpha_config.get('settings', {})
print(f"\n🚀 开始模拟: {name}")
print(f"📝 表达式: {expression}")
simulation_data = {
'type': 'REGULAR',
'settings': settings,
'regular': expression
}
try:
# 发送模拟数据
sim_resp = self.client.post(
f'{self.brain_api_url}/simulations',
json=simulation_data,
)
print(f"📤 模拟提交状态: {sim_resp.status_code}")
if sim_resp.status_code != 201:
print(f"❌ {name} 提交失败: {sim_resp.text}")
return {'name': name, 'success': False, 'error': f'提交失败: {sim_resp.status_code}'}
# 获取进度URL并轮询结果
sim_progress_url = sim_resp.headers['location']
print(f"⏳ {name} 进度URL获取成功")
while True:
sim_progress_resp = self.client.get(sim_progress_url)
retry_after_sec = float(sim_progress_resp.headers.get("Retry-After", 0))
if retry_after_sec == 0: # simulation done!
break
print(f"⏰ {name} 等待 {retry_after_sec} 秒...")
sleep(retry_after_sec)
# 获取最终的alpha ID
result_data = sim_progress_resp.json()
alpha_id = result_data["alpha"]
print(f"✅ {name} 模拟完成! Alpha ID: {alpha_id}")
return {
'name': name,
'expression': expression,
'alpha_id': alpha_id,
'success': True,
'result_data': result_data
}
except Exception as e:
print(f"❌ {name} 模拟过程中出错: {str(e)}")
return {'name': name, 'success': False, 'error': str(e)}
def _print_summary(self, results):
"""打印测试结果汇总"""
print("\n" + "=" * 50)
print("📊 Alpha测试结果汇总")
print("=" * 50)
success_count = sum(1 for r in results if r.get('success', False))
failed_count = len(results) - success_count
print(f"✅ 成功: {success_count} 个")
print(f"❌ 失败: {failed_count} 个")
print("\n成功详情:")
for result in results:
if result.get('success'):
print(f" ✓ {result['name']}: {result['alpha_id']}")
if failed_count > 0:
print("\n失败详情:")
for result in results:
if not result.get('success'):
print(f" ✗ {result['name']}: {result.get('error', '未知错误')}")
def close(self):
"""关闭客户端连接"""
if self.client:
self.client.close()
self.client = None
# 使用示例
if __name__ == "__main__":
# 创建API实例
wq_api = WorldQuantBrainAPI()
try:
# 1. 批量测试所有Alpha
print("🎯 开始批量测试Alpha因子...")
start_time = datetime.now()
results = wq_api.batch_simulate_alphas(
alphas_config_file='alphas.json',
max_workers=2 # 并发数量,根据API限制调整
)
end_time = datetime.now()
print(f"\n⏱️ 测试总耗时: {(end_time - start_time).total_seconds():.2f} 秒")
# 2. 提取成功的Alpha ID
successful_alphas = [r for r in results if r.get('success')]
alpha_ids = [r['alpha_id'] for r in successful_alphas]
print(f"\n📋 成功模拟的Alpha数量: {len(alpha_ids)}")
for alpha in successful_alphas:
print(f" - {alpha['name']}: {alpha['alpha_id']}")
except Exception as e:
print(f"❌ 程序执行出错: {str(e)}")
import traceback
traceback.print_exc() # 打印完整的错误堆栈
finally:
# 确保连接关闭
wq_api.close()
+100
View File
@@ -0,0 +1,100 @@
import httpx
import json
from httpx import BasicAuth
from time import sleep
class WorldQuantBrainAPI:
def __init__(self, credentials_file='brain_credentials.txt'):
self.credentials_file = credentials_file
self.client = None
self.brain_api_url = 'https://api.worldquantbrain.com'
def load_credentials(self):
"""读取本地账号密码"""
with open(self.credentials_file) as f:
credentials = eval(f.read())
return credentials[0], credentials[1]
def login(self):
"""登录认证"""
username, password = self.load_credentials()
self.client = httpx.Client(auth=BasicAuth(username, password))
response = self.client.post(f'{self.brain_api_url}/authentication')
print(f"登录状态: {response.status_code}")
if response.status_code == 201:
print("登录成功!")
return True
else:
print(f"登录失败: {response.json()}")
return False
def simulate_alpha(self, expression, settings=None):
"""模拟Alpha因子"""
if self.client is None:
raise Exception("请先登录")
default_settings = {
'instrumentType': 'EQUITY',
'region': 'USA',
'universe': 'TOP3000',
'delay': 1,
'decay': 0,
'neutralization': 'INDUSTRY',
'truncation': 0.08,
'pasteurization': 'ON',
'unitHandling': 'VERIFY',
'nanHandling': 'OFF',
'language': 'FASTEXPR',
'visualization': False,
}
if settings:
default_settings.update(settings)
simulation_data = {
'type': 'REGULAR',
'settings': default_settings,
'regular': expression
}
sim_resp = self.client.post(
f'{self.brain_api_url}/simulations',
json=simulation_data,
)
print(f"模拟提交状态: {sim_resp.status_code}")
sim_progress_url = sim_resp.headers['location']
print(f"进度URL: {sim_progress_url}")
while True:
sim_progress_resp = self.client.get(sim_progress_url)
retry_after_sec = float(sim_progress_resp.headers.get("Retry-After", 0))
if retry_after_sec == 0:
break
print(sim_progress_resp.json())
print(f"等待 {retry_after_sec} 秒...")
sleep(retry_after_sec)
alpha_id = sim_progress_resp.json()["alpha"]
print(f"生成的Alpha ID: {alpha_id}")
return alpha_id
def close(self):
"""关闭连接"""
if self.client:
self.client.close()
if __name__ == "__main__":
api = WorldQuantBrainAPI()
try:
# 读取账号密码并登录
if api.login():
# 模拟Alpha因子
alpha_id = api.simulate_alpha("liabilities/assets")
print(f"模拟完成,Alpha ID: {alpha_id}")
finally:
api.close()
+1
View File
@@ -0,0 +1 @@
null