update
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
['jack0210_@hotmail.com', '!QAZ2wsx+0913']
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -0,0 +1 @@
|
||||
null
|
||||
Reference in New Issue
Block a user