main
jack 4 weeks ago
parent 168298ace4
commit 83bac3cf78
  1. 4
      .gitignore
  2. 6
      alpha.txt
  3. 130
      core/api_client.py
  4. 7
      core/models.py
  5. 496
      main_bak.py
  6. 83
      managers/simulation_manager.py
  7. 139
      result/simulation_results-1763048082.json
  8. 289
      result/simulation_results-1763109446.json
  9. 524
      result/simulation_results-1763110929.json
  10. 82
      result/simulation_results-1763112962.json
  11. 12
      result/simulation_results-1763113286.json
  12. 4
      success.txt
  13. 45
      utils/file_utils.py

4
.gitignore vendored

@ -64,4 +64,6 @@ other/split_clash_config/split_config
ai_news/save_data
daily/*.txt
./result
./result
./alpha.txt
./account.txt

@ -1,5 +1 @@
ts_rank(ts_returns(close, 15), 30)
-ts_corr(ts_rank(close, 30), ts_rank(volume, 30), 10)
(close - ts_min(close, 20)) / (ts_max(close, 20) - ts_min(close, 20))
ts_rank(ts_delta(close, 3) / ts_delay(close, 3), 15)
-ts_std(ts_returns(close, 1), 30)
ts_delta(ts_mean(close, 5), 10) / ts_std(close, 20) * (ts_mean(close, 20) / ts_mean(close, 100) > 1.02)

@ -5,8 +5,6 @@ import time
from httpx import BasicAuth
from typing import Dict, Any, Optional, Tuple
from .models import AlphaMetrics, TrainMetrics, TestMetrics, AlphaInfo
class WorldQuantBrainSimulate:
def __init__(self, credentials_file='account.txt'):
@ -37,6 +35,7 @@ class WorldQuantBrainSimulate:
if response.status_code == 201:
print("登录成功!")
print(f"账户信息: {response.json()}")
return True
else:
print(f"登录失败: {response.json()}")
@ -83,7 +82,12 @@ class WorldQuantBrainSimulate:
if retry_after_sec == 0:
break
print(sim_progress_resp.json())
if sim_progress_resp.json():
result = sim_progress_resp.json()
progress = result['progress']
if progress:
print(f"模拟进度: {float(progress)*100}%")
print(f"等待 {retry_after_sec} 秒...")
time.sleep(retry_after_sec)
@ -103,7 +107,7 @@ class WorldQuantBrainSimulate:
return {"status": "success", "alpha_id": alpha_id, "metrics": metrics}
"""获取Alpha因子的详细指标"""
def get_alpha_metrics(self, alpha_id: str) -> AlphaMetrics:
def get_alpha_metrics(self, alpha_id: str) -> Dict[str, Any]:
if self.client is None:
raise Exception("请先登录")
@ -114,99 +118,39 @@ class WorldQuantBrainSimulate:
if alpha_resp.status_code in [200, 201]:
alpha_data = alpha_resp.json()
return self._parse_alpha_metrics(alpha_data)
# 以后可能需要获取其他参数
if alpha_data.get('metrics'):
alpha_data = alpha_data.get('metrics')
return alpha_data or {}
else:
return AlphaMetrics(
train_metrics=TrainMetrics(),
is_metrics=TestMetrics(),
test_metrics=TestMetrics(),
alpha_info=AlphaInfo()
)
print(f"获取Alpha指标失败: {alpha_resp.status_code}")
# 返回一个空的字典结构
return {
"train": {},
"is": {},
"test": {},
"grade": None,
"stage": None,
"status": None,
"dateCreated": None,
"id": alpha_id
}
except Exception as e:
print(f"获取指标时出错: {str(e)}")
return AlphaMetrics(
train_metrics=TrainMetrics(),
is_metrics=TestMetrics(),
test_metrics=TestMetrics(),
alpha_info=AlphaInfo()
)
"""解析Alpha数据,提取关键指标"""
def _parse_alpha_metrics(self, alpha_data: Dict[str, Any]) -> AlphaMetrics:
# 解析训练集数据
train_metrics = TrainMetrics()
if 'train' in alpha_data and alpha_data['train']:
train_data = alpha_data['train']
train_metrics = TrainMetrics(
sharpe_ratio=train_data.get('sharpe'),
annual_return=train_data.get('returns'),
max_drawdown=train_data.get('drawdown'),
turnover=train_data.get('turnover'),
fitness=train_data.get('fitness'),
pnl=train_data.get('pnl'),
book_size=train_data.get('bookSize'),
long_count=train_data.get('longCount'),
short_count=train_data.get('shortCount'),
margin=train_data.get('margin'),
)
# 解析样本内测试数据
is_metrics = TestMetrics()
if 'is' in alpha_data and alpha_data['is']:
is_data = alpha_data['is']
is_metrics = TestMetrics(
sharpe_ratio=is_data.get('sharpe'),
annual_return=is_data.get('returns'),
max_drawdown=is_data.get('drawdown'),
turnover=is_data.get('turnover'),
fitness=is_data.get('fitness'),
pnl=is_data.get('pnl'),
)
# 解析样本外测试数据
test_metrics = TestMetrics()
if 'test' in alpha_data and alpha_data['test']:
test_data = alpha_data['test']
test_metrics = TestMetrics(
sharpe_ratio=test_data.get('sharpe'),
annual_return=test_data.get('returns'),
max_drawdown=test_data.get('drawdown'),
turnover=test_data.get('turnover'),
fitness=test_data.get('fitness'),
pnl=test_data.get('pnl'),
)
# 解析Alpha基本信息
alpha_info = AlphaInfo(
grade=alpha_data.get('grade'),
stage=alpha_data.get('stage'),
status=alpha_data.get('status'),
date_created=alpha_data.get('dateCreated'),
)
# 解析检查结果
if 'is' in alpha_data and 'checks' in alpha_data['is']:
checks = alpha_data['is']['checks']
check_results = {}
for check in checks:
check_name = check.get('name', '')
result = check.get('result', '')
value = check.get('value', None)
check_results[check_name.lower()] = {
'result': result,
'value': value,
'limit': check.get('limit', None)
}
alpha_info.checks = check_results
return AlphaMetrics(
train_metrics=train_metrics,
is_metrics=is_metrics,
test_metrics=test_metrics,
alpha_info=alpha_info,
alpha_id=alpha_data.get('id')
)
# 返回一个空的字典结构
return {
"train": {},
"is": {},
"test": {},
"grade": None,
"stage": None,
"status": None,
"dateCreated": None,
"id": alpha_id
}
def close(self):
"""关闭连接"""

@ -56,10 +56,7 @@ class SimulationResult:
time_consuming: float
formatted_time: str
alpha_id: str
status: str # success, error, failed
status: str
description: str
simulation_timestamp: str
train_metrics: Optional[TrainMetrics] = None
is_metrics: Optional[TestMetrics] = None
test_metrics: Optional[TestMetrics] = None
alpha_info: Optional[AlphaInfo] = None
metrics: Optional[Dict[str, Any]] = None

@ -1,496 +0,0 @@
import os.path
import httpx
import json
from httpx import BasicAuth
import time
from random import uniform
import threading
from concurrent.futures import ThreadPoolExecutor, as_completed
class WorldQuantBrainSimulate:
def __init__(self, credentials_file='account.txt'):
self.credentials_file = credentials_file
self.client = None
self.brain_api_url = 'https://api.worldquantbrain.com'
"""读取本地账号密码"""
def load_credentials(self):
if not os.path.exists(self.credentials_file):
print("未找到 account.txt 文件")
with open(self.credentials_file, 'w') as f: f.write("")
print("account.txt 文件已创建,请填写账号密码, 格式: ['username', 'password]")
exit(1)
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
"""模拟Alpha因子"""
def simulate_alpha(self, expression, settings=None):
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} 秒...")
time.sleep(retry_after_sec)
# 如果因子模拟不通过, 获取一下失败信息
if sim_progress_resp.json()["status"] == "ERROR":
result = sim_progress_resp.json()["message"]
print(f"因子模拟失败: {result}")
# 返回一个特殊标识,表示模拟失败
return {"status": "error", "message": result}
alpha_id = sim_progress_resp.json()["alpha"]
print(f"生成的Alpha ID: {alpha_id}")
# 获取详细的性能指标
metrics = self.get_alpha_metrics(alpha_id)
return {"status": "success", "alpha_id": alpha_id, "metrics": metrics}
"""获取Alpha因子的详细指标"""
def get_alpha_metrics(self, alpha_id):
if self.client is None:
raise Exception("请先登录")
try:
# 获取Alpha的基本信息和指标
alpha_url = f'{self.brain_api_url}/alphas/{alpha_id}'
alpha_resp = self.client.get(alpha_url)
if alpha_resp.status_code in [200, 201]:
alpha_data = alpha_resp.json()
return self._parse_alpha_metrics(alpha_data)
else:
return {"error": f"无法获取Alpha信息: {alpha_resp.status_code}"}
except Exception as e:
return {"error": f"获取指标时出错: {str(e)}"}
"""解析Alpha数据,提取关键指标"""
def _parse_alpha_metrics(self, alpha_data):
metrics = {}
try:
# 从train字段获取指标数据
if 'train' in alpha_data and alpha_data['train']:
train_data = alpha_data['train']
metrics.update({
'sharpe_ratio': train_data.get('sharpe', None),
'annual_return': train_data.get('returns', None),
'max_drawdown': train_data.get('drawdown', None),
'turnover': train_data.get('turnover', None),
'fitness': train_data.get('fitness', None),
'pnl': train_data.get('pnl', None),
'book_size': train_data.get('bookSize', None),
'long_count': train_data.get('longCount', None),
'short_count': train_data.get('shortCount', None),
'margin': train_data.get('margin', None),
'start_date': train_data.get('startDate', None),
})
# 从is字段获取样本内测试数据
if 'is' in alpha_data and alpha_data['is']:
is_data = alpha_data['is']
metrics.update({
'is_sharpe': is_data.get('sharpe', None),
'is_returns': is_data.get('returns', None),
'is_drawdown': is_data.get('drawdown', None),
'is_turnover': is_data.get('turnover', None),
'is_fitness': is_data.get('fitness', None),
'is_pnl': is_data.get('pnl', None),
})
# 从test字段获取样本外测试数据
if 'test' in alpha_data and alpha_data['test']:
test_data = alpha_data['test']
metrics.update({
'test_sharpe': test_data.get('sharpe', None),
'test_returns': test_data.get('returns', None),
'test_drawdown': test_data.get('drawdown', None),
'test_turnover': test_data.get('turnover', None),
'test_fitness': test_data.get('fitness', None),
'test_pnl': test_data.get('pnl', None),
})
# 其他重要信息
metrics.update({
'alpha_id': alpha_data.get('id', None),
'grade': alpha_data.get('grade', None),
'stage': alpha_data.get('stage', None),
'status': alpha_data.get('status', None),
'date_created': alpha_data.get('dateCreated', None),
})
# 解析检查结果
if 'is' in alpha_data and 'checks' in alpha_data['is']:
checks = alpha_data['is']['checks']
check_results = {}
for check in checks:
check_name = check.get('name', '')
result = check.get('result', '')
value = check.get('value', None)
check_results[check_name.lower()] = {
'result': result,
'value': value,
'limit': check.get('limit', None)
}
metrics['checks'] = check_results
except Exception as e:
metrics['error'] = f"解析指标时出错: {str(e)}"
return metrics
def close(self):
"""关闭连接"""
if self.client:
self.client.close()
class AlphaSimulationManager:
def __init__(self, credentials_file='account.txt'):
self.credentials_file = credentials_file
self.results = []
"""将秒数格式化为 xx分xx秒 格式"""
def format_time(self, seconds):
if seconds < 60:
return f"{seconds:.2f}"
else:
minutes = int(seconds // 60)
remaining_seconds = seconds % 60
return f"{minutes}{remaining_seconds:.2f}"
"""模拟单个Alpha因子(线程安全)"""
def simulate_single_alpha(self, api, expression, settings=None):
alpha_start_time = time.time()
try:
# 模拟Alpha因子
simulation_result = api.simulate_alpha(expression, settings)
alpha_end_time = time.time()
time_consuming = alpha_end_time - alpha_start_time
# 根据模拟结果类型处理
if simulation_result["status"] == "success":
# 模拟成功的结果
result = {
"expression": expression,
"time_consuming": time_consuming,
"formatted_time": self.format_time(time_consuming),
"alpha_id": simulation_result["alpha_id"],
"status": "success",
"description": "/",
"simulation_timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
# 训练集指标
"train_metrics": {
"sharpe_ratio": simulation_result["metrics"].get('sharpe_ratio'),
"annual_return": simulation_result["metrics"].get('annual_return'),
"max_drawdown": simulation_result["metrics"].get('max_drawdown'),
"turnover": simulation_result["metrics"].get('turnover'),
"fitness": simulation_result["metrics"].get('fitness'),
"pnl": simulation_result["metrics"].get('pnl'),
"book_size": simulation_result["metrics"].get('book_size'),
"long_count": simulation_result["metrics"].get('long_count'),
"short_count": simulation_result["metrics"].get('short_count'),
"margin": simulation_result["metrics"].get('margin'),
},
# 样本内测试指标
"is_metrics": {
"sharpe_ratio": simulation_result["metrics"].get('is_sharpe'),
"annual_return": simulation_result["metrics"].get('is_returns'),
"max_drawdown": simulation_result["metrics"].get('is_drawdown'),
"turnover": simulation_result["metrics"].get('is_turnover'),
"fitness": simulation_result["metrics"].get('is_fitness'),
"pnl": simulation_result["metrics"].get('is_pnl'),
},
# 样本外测试指标
"test_metrics": {
"sharpe_ratio": simulation_result["metrics"].get('test_sharpe'),
"annual_return": simulation_result["metrics"].get('test_returns'),
"max_drawdown": simulation_result["metrics"].get('test_drawdown'),
"turnover": simulation_result["metrics"].get('test_turnover'),
"fitness": simulation_result["metrics"].get('test_fitness'),
"pnl": simulation_result["metrics"].get('test_pnl'),
},
# 其他信息
"alpha_info": {
"grade": simulation_result["metrics"].get('grade'),
"stage": simulation_result["metrics"].get('stage'),
"status": simulation_result["metrics"].get('status'),
"date_created": simulation_result["metrics"].get('date_created'),
"checks": simulation_result["metrics"].get('checks', {})
}
}
print(f"✓ 因子模拟成功: {expression}")
print(f" 耗时: {self.format_time(time_consuming)},Alpha ID: {simulation_result['alpha_id']}")
# 打印关键指标
self._print_success_metrics(simulation_result["metrics"])
else:
# 模拟失败的结果(API返回的错误)
result = {
"expression": expression,
"time_consuming": time_consuming,
"formatted_time": self.format_time(time_consuming),
"alpha_id": "/",
"status": "error",
"description": simulation_result["message"],
"simulation_timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"performance_metrics": {},
"risk_metrics": {},
"quantile_metrics": {},
"other_metrics": {}
}
print(f"✗ 因子模拟失败: {expression}")
print(f" 耗时: {self.format_time(time_consuming)},错误: {simulation_result['message']}")
except Exception as e:
# 其他异常情况
alpha_end_time = time.time()
time_consuming = alpha_end_time - alpha_start_time
result = {
"expression": expression,
"time_consuming": time_consuming,
"formatted_time": self.format_time(time_consuming),
"alpha_id": "/",
"status": "failed",
"description": str(e),
"simulation_timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"performance_metrics": {},
"risk_metrics": {},
"quantile_metrics": {},
"other_metrics": {}
}
print(f"✗ 因子模拟异常: {expression}")
print(f" 耗时: {self.format_time(time_consuming)},异常: {str(e)}")
return result
"""打印成功因子的关键指标"""
def _print_success_metrics(self, metrics):
if 'error' in metrics:
print(f" 指标获取错误: {metrics['error']}")
return
print(" 关键指标 (训练集):")
key_metrics = [
('夏普比率', 'sharpe_ratio'),
('年化收益', 'annual_return'),
('最大回撤', 'max_drawdown'),
('换手率', 'turnover'),
('适应度', 'fitness'),
('PNL', 'pnl'),
]
for chinese_name, metric_key in key_metrics:
value = metrics.get(metric_key)
if value is not None:
if isinstance(value, float):
value = f"{value:.4f}"
print(f" {chinese_name}: {value}")
# 显示样本外测试的夏普比率(如果存在)
test_sharpe = metrics.get('test_sharpe')
if test_sharpe is not None:
print(f" 样本外夏普比率: {test_sharpe:.4f}")
"""模拟一批Alpha因子(3个一组)"""
def simulate_alpha_batch(self, alpha_batch, batch_number):
print(f"\n{'=' * 60}")
print(f"开始第 {batch_number} 批因子模拟 (共 {len(alpha_batch)} 个因子)")
print(f"因子列表: {alpha_batch}")
print(f"{'=' * 60}")
batch_start_time = time.time()
batch_results = []
# 创建API客户端实例(每个线程独立的客户端)
api = WorldQuantBrainSimulate(self.credentials_file)
try:
if api.login():
# 使用线程池执行3个因子的模拟
with ThreadPoolExecutor(max_workers=3) as executor:
# 提交所有任务
future_to_alpha = {executor.submit(self.simulate_single_alpha, api, alpha): alpha for alpha in alpha_batch}
# 等待所有任务完成
for future in as_completed(future_to_alpha):
alpha = future_to_alpha[future]
try:
result = future.result()
batch_results.append(result)
except Exception as e:
print(f"因子 {alpha} 执行异常: {e}")
except Exception as e:
print(f"{batch_number} 批模拟过程中出错: {e}")
finally:
api.close()
batch_end_time = time.time()
batch_total_time = batch_end_time - batch_start_time
print(f"\n{batch_number} 批模拟完成!")
print(f"本批总耗时: {self.format_time(batch_total_time)}")
print(f"{'=' * 60}")
return batch_results
"""运行批量模拟"""
def run_simulation(self, alpha_list, batch_size=3):
print("开始Alpha因子批量模拟...")
total_start_time = time.time()
# 将因子列表分成每批3个
batches = [alpha_list[i:i + batch_size] for i in range(0, len(alpha_list), batch_size)]
all_results = []
for i, batch in enumerate(batches, 1):
# 模拟当前批次
batch_results = self.simulate_alpha_batch(batch, i)
all_results.extend(batch_results)
# 如果不是最后一批,则等待3-5秒
if i < len(batches):
sleep_time = uniform(3, 5)
print(f"\n等待 {sleep_time:.2f} 秒后开始下一批...")
time.sleep(sleep_time)
total_end_time = time.time()
total_time = total_end_time - total_start_time
# 输出最终结果汇总
self.print_summary(all_results, total_time)
# 保存结果到文件
self.save_results(all_results)
return all_results
"""打印结果汇总"""
def print_summary(self, results, total_time):
print(f"\n{'=' * 60}")
print("模拟结果汇总")
print(f"{'=' * 60}")
success_count = sum(1 for r in results if r['status'] == 'success')
error_count = sum(1 for r in results if r['status'] == 'error')
failed_count = sum(1 for r in results if r['status'] == 'failed')
print(f"总模拟因子数: {len(results)}")
print(f"成功: {success_count}")
print(f"模拟错误: {error_count}")
print(f"执行异常: {failed_count}")
print(f"总耗时: {self.format_time(total_time)}")
print(f"{'=' * 60}")
for i, result in enumerate(results, 1):
status_icon = "" if result['status'] == 'success' else ""
print(f"{i}. {status_icon} {result['expression']}")
print(f" 状态: {result['status']}")
print(f" 耗时: {result['formatted_time']}")
print(f" Alpha ID: {result['alpha_id']}")
if result['status'] != 'success':
print(f" 原因: {result['description']}")
print()
"""保存结果到文件"""
def save_results(self, results):
# 转换为可序列化的格式
serializable_results = []
for result in results:
serializable_result = result.copy()
serializable_result['time_consuming'] = round(serializable_result['time_consuming'], 2)
# 处理metrics中的浮点数,保留6位小数
for metric_category in ['performance_metrics', 'risk_metrics', 'quantile_metrics', 'other_metrics']:
if metric_category in serializable_result:
for key, value in serializable_result[metric_category].items():
if isinstance(value, float):
serializable_result[metric_category][key] = round(value, 6)
serializable_results.append(serializable_result)
# 将日志文件, 保存到当前目录下, result 文件夹中
if not os.path.exists('./result'):
os.makedirs('./result')
result_name = f"result/simulation_results-{str(int(time.time()))}.json"
with open(result_name, 'w', encoding='utf-8') as f:
json.dump(serializable_results, f, ensure_ascii=False, indent=2)
print(f"结果已保存到 {result_name}")
if __name__ == "__main__":
# 待模拟因子列表
with open('alpha.txt', 'r', encoding='utf-8') as file:
alpha_list = [line.strip() for line in file]
if not alpha_list:
print("alpha.txt 文件不存在")
with open('alpha.txt', 'w', encoding='utf-8') as file: file.write("")
print("已创建 alpha.txt 文件, 请添加因子后重新运行, 一行一个因子")
exit(1)
# 创建模拟管理器并运行
manager = AlphaSimulationManager()
results = manager.run_simulation(alpha_list, batch_size=3)

@ -7,9 +7,9 @@ from random import uniform
from typing import List, Dict, Any
from core.api_client import WorldQuantBrainSimulate
from core.models import SimulationResult, TrainMetrics, TestMetrics, AlphaInfo
from core.models import SimulationResult
from utils.time_utils import format_time
from utils.file_utils import save_results_to_file
from utils.file_utils import save_results_to_file, save_success_alpha
class AlphaSimulationManager:
@ -19,7 +19,7 @@ class AlphaSimulationManager:
"""模拟单个Alpha因子(线程安全)"""
def simulate_single_alpha(self, api: WorldQuantBrainSimulate, expression: str,
settings: Dict[str, Any] = None) -> SimulationResult:
settings: Dict[str, Any] = None) -> SimulationResult:
alpha_start_time = time.time()
try:
@ -30,7 +30,7 @@ class AlphaSimulationManager:
# 根据模拟结果类型处理
if simulation_result["status"] == "success":
# 模拟成功的结果
# 模拟成功的结果 - 直接使用原始metrics数据
metrics = simulation_result["metrics"]
result = SimulationResult(
expression=expression,
@ -40,10 +40,7 @@ class AlphaSimulationManager:
status="success",
description="/",
simulation_timestamp=time.strftime("%Y-%m-%d %H:%M:%S"),
train_metrics=metrics.train_metrics,
is_metrics=metrics.is_metrics,
test_metrics=metrics.test_metrics,
alpha_info=metrics.alpha_info
metrics=metrics # 直接存储原始metrics数据
)
print(f"✓ 因子模拟成功: {expression}")
print(f" 耗时: {format_time(time_consuming)},Alpha ID: {simulation_result['alpha_id']}")
@ -60,7 +57,8 @@ class AlphaSimulationManager:
alpha_id="/",
status="error",
description=simulation_result["message"],
simulation_timestamp=time.strftime("%Y-%m-%d %H:%M:%S")
simulation_timestamp=time.strftime("%Y-%m-%d %H:%M:%S"),
metrics=None
)
print(f"✗ 因子模拟失败: {expression}")
print(f" 耗时: {format_time(time_consuming)},错误: {simulation_result['message']}")
@ -77,7 +75,8 @@ class AlphaSimulationManager:
alpha_id="/",
status="failed",
description=str(e),
simulation_timestamp=time.strftime("%Y-%m-%d %H:%M:%S")
simulation_timestamp=time.strftime("%Y-%m-%d %H:%M:%S"),
metrics=None
)
print(f"✗ 因子模拟异常: {expression}")
print(f" 耗时: {format_time(time_consuming)},异常: {str(e)}")
@ -85,37 +84,45 @@ class AlphaSimulationManager:
return result
"""打印成功因子的关键指标"""
def _print_success_metrics(self, metrics):
def _print_success_metrics(self, metrics: Dict[str, Any]):
# 添加空值检查
if not metrics:
print(" 无指标数据")
return
print(" 关键指标 (训练集):")
# 从原始metrics数据中提取训练集指标
train_data = metrics.get('train', {}) or {}
key_metrics = [
('夏普比率', metrics.train_metrics.sharpe_ratio),
('年化收益', metrics.train_metrics.annual_return),
('最大回撤', metrics.train_metrics.max_drawdown),
('换手率', metrics.train_metrics.turnover),
('适应度', metrics.train_metrics.fitness),
('PNL', metrics.train_metrics.pnl),
('夏普比率', train_data.get('sharpe')),
('年化收益', train_data.get('returns')),
('最大回撤', train_data.get('drawdown')),
('换手率', train_data.get('turnover')),
('适应度', train_data.get('fitness')),
('PNL', train_data.get('pnl')),
]
for chinese_name, value in key_metrics:
if value is not None:
if isinstance(value, float):
value = f"{value:.4f}"
print(f" {chinese_name}: {value}")
# 显示样本外测试的夏普比率(如果存在)
if metrics.test_metrics.sharpe_ratio is not None:
print(f" 样本外夏普比率: {metrics.test_metrics.sharpe_ratio:.4f}")
print(f" {chinese_name}: {value}") # 衡量风险调整后的收益
# 年化收益率
# 显示样本外测试的夏普比率(如果存在) # 最大亏损幅度
test_data = metrics.get('test', {}) or {} # 交易频率
if test_data.get('sharpe') is not None: # 策略适应度得分
print(f" 样本外夏普比率: {test_data.get('sharpe'):.4f}") # 净盈亏
"""模拟一批Alpha因子(3个一组)"""
def simulate_alpha_batch(self, alpha_batch: List[str], batch_number: int) -> List[SimulationResult]:
print(f"\n{'=' * 60}")
print(f"开始第 {batch_number} 批因子模拟 (共 {len(alpha_batch)} 个因子)")
print(f"\n{'=' * 60}") # 只打印存在的指标
print(f"开始第 {batch_number} 批因子模拟 (共 {len(alpha_batch)} 个因子)") # 格式化浮点数显示
print(f"因子列表: {alpha_batch}")
print(f"{'=' * 60}")
batch_start_time = time.time()
batch_results = []
# 检查是否存在测试集夏普比率
# 创建API客户端实例(每个线程独立的客户端)
api = WorldQuantBrainSimulate(self.credentials_file)
@ -200,12 +207,26 @@ class AlphaSimulationManager:
print(f"总耗时: {format_time(total_time)}")
print(f"{'=' * 60}")
success_expression_list = []
for i, result in enumerate(results, 1):
status_icon = "" if result.status == 'success' else ""
print(f"{i}. {status_icon} {result.expression}")
print(f" 状态: {result.status}")
print(f" 耗时: {result.formatted_time}")
print(f" Alpha ID: {result.alpha_id}")
if result.status == 'success':
success_expression_list.append(result.expression)
line_parts = [
f"{i}. {status_icon} {result.expression}",
f"状态: {result.status}",
f"耗时: {result.formatted_time}"
]
if result.alpha_id != '/':
line_parts.append(f"Alpha ID: {result.alpha_id}")
if result.status != 'success':
print(f" 原因: {result.description}")
print()
line_parts.append(f"原因: {result.description}")
print("\t".join(line_parts))
save_success_alpha(success_expression_list)

@ -1,139 +0,0 @@
[
{
"expression": "ts_rank(ts_returns(close, 15), 30)",
"time_consuming": 5.89,
"formatted_time": "5.89秒",
"alpha_id": "/",
"status": "error",
"description": "Attempted to use inaccessible or unknown operator \"ts_returns\"",
"simulation_timestamp": "2025-11-13 23:30:43",
"train_metrics": null,
"is_metrics": null,
"test_metrics": null,
"alpha_info": null
},
{
"expression": "(close - ts_min(close, 20)) / (ts_max(close, 20) - ts_min(close, 20))",
"time_consuming": 7.89,
"formatted_time": "7.89秒",
"alpha_id": "/",
"status": "error",
"description": "Attempted to use inaccessible or unknown operator \"ts_min\"",
"simulation_timestamp": "2025-11-13 23:30:45",
"train_metrics": null,
"is_metrics": null,
"test_metrics": null,
"alpha_info": null
},
{
"expression": "-ts_corr(ts_rank(close, 30), ts_rank(volume, 30), 10)",
"time_consuming": 88.99,
"formatted_time": "1分28.99秒",
"alpha_id": "JjEVlkNx",
"status": "success",
"description": "/",
"simulation_timestamp": "2025-11-13 23:32:06",
"train_metrics": {
"sharpe_ratio": null,
"annual_return": null,
"max_drawdown": null,
"turnover": null,
"fitness": null,
"pnl": null,
"book_size": null,
"long_count": null,
"short_count": null,
"margin": null
},
"is_metrics": {
"sharpe_ratio": 1.15,
"annual_return": 0.0604,
"max_drawdown": 0.1311,
"turnover": 0.4517,
"fitness": 0.42,
"pnl": 2988907
},
"test_metrics": {
"sharpe_ratio": null,
"annual_return": null,
"max_drawdown": null,
"turnover": null,
"fitness": null,
"pnl": null
},
"alpha_info": {
"grade": "INFERIOR",
"stage": "IS",
"status": "UNSUBMITTED",
"date_created": "2025-11-13T10:32:05-05:00",
"checks": {
"low_sharpe": {
"result": "FAIL",
"value": 1.15,
"limit": 1.25
},
"low_fitness": {
"result": "FAIL",
"value": 0.42,
"limit": 1.0
},
"low_turnover": {
"result": "PASS",
"value": 0.4517,
"limit": 0.01
},
"high_turnover": {
"result": "PASS",
"value": 0.4517,
"limit": 0.7
},
"concentrated_weight": {
"result": "PASS",
"value": null,
"limit": null
},
"low_sub_universe_sharpe": {
"result": "PASS",
"value": 0.76,
"limit": 0.5
},
"self_correlation": {
"result": "PENDING",
"value": null,
"limit": null
},
"matches_competition": {
"result": "PASS",
"value": null,
"limit": null
}
}
}
},
{
"expression": "-ts_std(ts_returns(close, 1), 30)",
"time_consuming": 1.42,
"formatted_time": "1.42秒",
"alpha_id": "/",
"status": "error",
"description": "Attempted to use inaccessible or unknown operator \"ts_std\"",
"simulation_timestamp": "2025-11-13 23:32:15",
"train_metrics": null,
"is_metrics": null,
"test_metrics": null,
"alpha_info": null
},
{
"expression": "ts_rank(ts_delta(close, 3) / ts_delay(close, 3), 15)",
"time_consuming": 148.04,
"formatted_time": "2分28.04秒",
"alpha_id": "/",
"status": "failed",
"description": "_ssl.c:980: The handshake operation timed out",
"simulation_timestamp": "2025-11-13 23:34:42",
"train_metrics": null,
"is_metrics": null,
"test_metrics": null,
"alpha_info": null
}
]

@ -0,0 +1,289 @@
[
{
"expression": "-ts_correlation(open, close, 20)",
"time_consuming": 21.09,
"formatted_time": "21.09秒",
"alpha_id": "/",
"status": "error",
"description": "Attempted to use inaccessible or unknown operator \"ts_correlation\"",
"simulation_timestamp": "2025-11-14 16:35:40",
"metrics": null
},
{
"expression": "ts_mean(volume / ts_mean(volume, 20), 30)",
"time_consuming": 90.94,
"formatted_time": "1分30.94秒",
"alpha_id": "akZ63dm1",
"status": "success",
"description": "/",
"simulation_timestamp": "2025-11-14 16:36:50",
"metrics": {
"id": "akZ63dm1",
"type": "REGULAR",
"author": "YC93384",
"settings": {
"instrumentType": "EQUITY",
"region": "USA",
"universe": "TOP3000",
"delay": 1,
"decay": 0,
"neutralization": "INDUSTRY",
"truncation": 0.08,
"pasteurization": "ON",
"unitHandling": "VERIFY",
"nanHandling": "OFF",
"maxTrade": "OFF",
"language": "FASTEXPR",
"visualization": false,
"startDate": "2018-01-20",
"endDate": "2023-01-20"
},
"regular": {
"code": "ts_mean(volume / ts_mean(volume, 20), 30)",
"description": null,
"operatorCount": 3
},
"dateCreated": "2025-11-14T03:36:48-05:00",
"dateSubmitted": null,
"dateModified": "2025-11-14T03:36:48-05:00",
"name": null,
"favorite": false,
"hidden": false,
"color": null,
"category": null,
"tags": [],
"classifications": [
{
"id": "DATA_USAGE:SINGLE_DATA_SET",
"name": "Single Data Set Alpha"
}
],
"grade": "INFERIOR",
"stage": "IS",
"status": "UNSUBMITTED",
"is": {
"pnl": 752501,
"bookSize": 20000000,
"longCount": 1462,
"shortCount": 1666,
"turnover": 0.1707,
"returns": 0.0152,
"drawdown": 0.1146,
"margin": 0.000178,
"sharpe": 0.25,
"fitness": 0.07,
"startDate": "2018-01-20",
"checks": [
{
"name": "LOW_SHARPE",
"result": "FAIL",
"limit": 1.25,
"value": 0.25
},
{
"name": "LOW_FITNESS",
"result": "FAIL",
"limit": 1.0,
"value": 0.07
},
{
"name": "LOW_TURNOVER",
"result": "PASS",
"limit": 0.01,
"value": 0.1707
},
{
"name": "HIGH_TURNOVER",
"result": "PASS",
"limit": 0.7,
"value": 0.1707
},
{
"name": "CONCENTRATED_WEIGHT",
"result": "PASS"
},
{
"name": "LOW_SUB_UNIVERSE_SHARPE",
"result": "PASS",
"limit": 0.11,
"value": 0.83
},
{
"name": "SELF_CORRELATION",
"result": "PENDING"
},
{
"name": "MATCHES_COMPETITION",
"result": "PASS",
"competitions": [
{
"id": "challenge",
"name": "Challenge"
}
]
}
]
},
"os": null,
"train": null,
"test": null,
"prod": null,
"competitions": null,
"themes": null,
"pyramids": null,
"pyramidThemes": null,
"team": null
}
},
{
"expression": "ts_rank((high - low) / (close - open + 0.001), 15)",
"time_consuming": 116.93,
"formatted_time": "1分56.93秒",
"alpha_id": "VkjVoGGb",
"status": "success",
"description": "/",
"simulation_timestamp": "2025-11-14 16:37:16",
"metrics": {
"id": "VkjVoGGb",
"type": "REGULAR",
"author": "YC93384",
"settings": {
"instrumentType": "EQUITY",
"region": "USA",
"universe": "TOP3000",
"delay": 1,
"decay": 0,
"neutralization": "INDUSTRY",
"truncation": 0.08,
"pasteurization": "ON",
"unitHandling": "VERIFY",
"nanHandling": "OFF",
"maxTrade": "OFF",
"language": "FASTEXPR",
"visualization": false,
"startDate": "2018-01-20",
"endDate": "2023-01-20"
},
"regular": {
"code": "ts_rank((high - low) / (close - open + 0.001), 15)",
"description": null,
"operatorCount": 5
},
"dateCreated": "2025-11-14T03:37:13-05:00",
"dateSubmitted": null,
"dateModified": "2025-11-14T03:37:14-05:00",
"name": null,
"favorite": false,
"hidden": false,
"color": null,
"category": null,
"tags": [],
"classifications": [
{
"id": "DATA_USAGE:SINGLE_DATA_SET",
"name": "Single Data Set Alpha"
}
],
"grade": "INFERIOR",
"stage": "IS",
"status": "UNSUBMITTED",
"is": {
"pnl": -1933631,
"bookSize": 20000000,
"longCount": 1562,
"shortCount": 1565,
"turnover": 1.3813,
"returns": -0.0391,
"drawdown": 0.2222,
"margin": -5.7e-05,
"sharpe": -1.15,
"fitness": -0.19,
"startDate": "2018-01-20",
"checks": [
{
"name": "LOW_SHARPE",
"result": "FAIL",
"limit": 1.25,
"value": -1.15
},
{
"name": "LOW_FITNESS",
"result": "FAIL",
"limit": 1.0,
"value": -0.19
},
{
"name": "LOW_TURNOVER",
"result": "PASS",
"limit": 0.01,
"value": 1.3813
},
{
"name": "HIGH_TURNOVER",
"result": "FAIL",
"limit": 0.7,
"value": 1.3813
},
{
"name": "CONCENTRATED_WEIGHT",
"result": "PASS"
},
{
"name": "LOW_SUB_UNIVERSE_SHARPE",
"result": "FAIL",
"limit": -0.5,
"value": -0.73
},
{
"name": "UNITS",
"result": "WARNING",
"message": "Incompatible unit for input of \"add\" at index 1, expected \"Unit[CSPrice:1]\", found \"Unit[]\""
},
{
"name": "SELF_CORRELATION",
"result": "PENDING"
},
{
"name": "MATCHES_COMPETITION",
"result": "PASS",
"competitions": [
{
"id": "challenge",
"name": "Challenge"
}
]
}
]
},
"os": null,
"train": null,
"test": null,
"prod": null,
"competitions": null,
"themes": null,
"pyramids": null,
"pyramidThemes": null,
"team": null
}
},
{
"expression": "-ts_rank(ts_skewness(returns(close), 10), 25)",
"time_consuming": 1.44,
"formatted_time": "1.44秒",
"alpha_id": "/",
"status": "error",
"description": "Attempted to use inaccessible or unknown operator \"ts_skewness\"",
"simulation_timestamp": "2025-11-14 16:37:22",
"metrics": null
},
{
"expression": "(close - ts_min(low, 50)) / (ts_max(high, 50) - ts_min(low, 50) + 0.001)",
"time_consuming": 5.76,
"formatted_time": "5.76秒",
"alpha_id": "/",
"status": "error",
"description": "Attempted to use inaccessible or unknown operator \"ts_min\"",
"simulation_timestamp": "2025-11-14 16:37:26",
"metrics": null
}
]

@ -0,0 +1,524 @@
[
{
"expression": "ts_rank(close - vwap, 12)",
"time_consuming": 15.79,
"formatted_time": "15.79秒",
"alpha_id": "/",
"status": "failed",
"description": "The read operation timed out",
"simulation_timestamp": "2025-11-14 16:58:48",
"metrics": null
},
{
"expression": "ts_mean((close - open) / (high - low + 0.001), 20)",
"time_consuming": 109.71,
"formatted_time": "1分49.71秒",
"alpha_id": "VkjVwxrG",
"status": "success",
"description": "/",
"simulation_timestamp": "2025-11-14 17:00:22",
"metrics": {
"id": "VkjVwxrG",
"type": "REGULAR",
"author": "YC93384",
"settings": {
"instrumentType": "EQUITY",
"region": "USA",
"universe": "TOP3000",
"delay": 1,
"decay": 0,
"neutralization": "INDUSTRY",
"truncation": 0.08,
"pasteurization": "ON",
"unitHandling": "VERIFY",
"nanHandling": "OFF",
"maxTrade": "OFF",
"language": "FASTEXPR",
"visualization": false,
"startDate": "2018-01-20",
"endDate": "2023-01-20"
},
"regular": {
"code": "ts_mean((close - open) / (high - low + 0.001), 20)",
"description": null,
"operatorCount": 5
},
"dateCreated": "2025-11-14T04:00:17-05:00",
"dateSubmitted": null,
"dateModified": "2025-11-14T04:00:18-05:00",
"name": null,
"favorite": false,
"hidden": false,
"color": null,
"category": null,
"tags": [],
"classifications": [
{
"id": "DATA_USAGE:SINGLE_DATA_SET",
"name": "Single Data Set Alpha"
}
],
"grade": "INFERIOR",
"stage": "IS",
"status": "UNSUBMITTED",
"is": {
"pnl": -4252305,
"bookSize": 20000000,
"longCount": 1570,
"shortCount": 1558,
"turnover": 0.3075,
"returns": -0.0859,
"drawdown": 0.5096,
"margin": -0.000559,
"sharpe": -0.83,
"fitness": -0.44,
"startDate": "2018-01-20",
"checks": [
{
"name": "LOW_SHARPE",
"result": "FAIL",
"limit": 1.25,
"value": -0.83
},
{
"name": "LOW_FITNESS",
"result": "FAIL",
"limit": 1.0,
"value": -0.44
},
{
"name": "LOW_TURNOVER",
"result": "PASS",
"limit": 0.01,
"value": 0.3075
},
{
"name": "HIGH_TURNOVER",
"result": "PASS",
"limit": 0.7,
"value": 0.3075
},
{
"name": "CONCENTRATED_WEIGHT",
"result": "PASS"
},
{
"name": "LOW_SUB_UNIVERSE_SHARPE",
"result": "FAIL",
"limit": -0.36,
"value": -0.7
},
{
"name": "UNITS",
"result": "WARNING",
"message": "Incompatible unit for input of \"add\" at index 1, expected \"Unit[CSPrice:1]\", found \"Unit[]\""
},
{
"name": "SELF_CORRELATION",
"result": "PENDING"
},
{
"name": "MATCHES_COMPETITION",
"result": "PASS",
"competitions": [
{
"id": "challenge",
"name": "Challenge"
}
]
}
]
},
"os": null,
"train": null,
"test": null,
"prod": null,
"competitions": null,
"themes": null,
"pyramids": null,
"pyramidThemes": null,
"team": null
}
},
{
"expression": "-ts_rank(ts_decay_linear(volume, 10), 30)",
"time_consuming": 124.43,
"formatted_time": "2分4.43秒",
"alpha_id": "E5W10mem",
"status": "success",
"description": "/",
"simulation_timestamp": "2025-11-14 17:00:37",
"metrics": {
"id": "E5W10mem",
"type": "REGULAR",
"author": "YC93384",
"settings": {
"instrumentType": "EQUITY",
"region": "USA",
"universe": "TOP3000",
"delay": 1,
"decay": 0,
"neutralization": "INDUSTRY",
"truncation": 0.08,
"pasteurization": "ON",
"unitHandling": "VERIFY",
"nanHandling": "OFF",
"maxTrade": "OFF",
"language": "FASTEXPR",
"visualization": false,
"startDate": "2018-01-20",
"endDate": "2023-01-20"
},
"regular": {
"code": "-ts_rank(ts_decay_linear(volume, 10), 30)",
"description": null,
"operatorCount": 3
},
"dateCreated": "2025-11-14T04:00:33-05:00",
"dateSubmitted": null,
"dateModified": "2025-11-14T04:00:34-05:00",
"name": null,
"favorite": false,
"hidden": false,
"color": null,
"category": null,
"tags": [],
"classifications": [
{
"id": "DATA_USAGE:SINGLE_DATA_SET",
"name": "Single Data Set Alpha"
}
],
"grade": "INFERIOR",
"stage": "IS",
"status": "UNSUBMITTED",
"is": {
"pnl": -1352690,
"bookSize": 20000000,
"longCount": 1610,
"shortCount": 1517,
"turnover": 0.3383,
"returns": -0.0273,
"drawdown": 0.2176,
"margin": -0.000162,
"sharpe": -0.58,
"fitness": -0.16,
"startDate": "2018-01-20",
"checks": [
{
"name": "LOW_SHARPE",
"result": "FAIL",
"limit": 1.25,
"value": -0.58
},
{
"name": "LOW_FITNESS",
"result": "FAIL",
"limit": 1.0,
"value": -0.16
},
{
"name": "LOW_TURNOVER",
"result": "PASS",
"limit": 0.01,
"value": 0.3383
},
{
"name": "HIGH_TURNOVER",
"result": "PASS",
"limit": 0.7,
"value": 0.3383
},
{
"name": "CONCENTRATED_WEIGHT",
"result": "PASS"
},
{
"name": "LOW_SUB_UNIVERSE_SHARPE",
"result": "FAIL",
"limit": -0.25,
"value": -0.66
},
{
"name": "SELF_CORRELATION",
"result": "PENDING"
},
{
"name": "MATCHES_COMPETITION",
"result": "PASS",
"competitions": [
{
"id": "challenge",
"name": "Challenge"
}
]
}
]
},
"os": null,
"train": null,
"test": null,
"prod": null,
"competitions": null,
"themes": null,
"pyramids": null,
"pyramidThemes": null,
"team": null
}
},
{
"expression": "ts_rank(adv20 - volume, 15) + ts_rank(volume, 15)",
"time_consuming": 85.26,
"formatted_time": "1分25.26秒",
"alpha_id": "0m3qkZN1",
"status": "success",
"description": "/",
"simulation_timestamp": "2025-11-14 17:02:08",
"metrics": {
"id": "0m3qkZN1",
"type": "REGULAR",
"author": "YC93384",
"settings": {
"instrumentType": "EQUITY",
"region": "USA",
"universe": "TOP3000",
"delay": 1,
"decay": 0,
"neutralization": "INDUSTRY",
"truncation": 0.08,
"pasteurization": "ON",
"unitHandling": "VERIFY",
"nanHandling": "OFF",
"maxTrade": "OFF",
"language": "FASTEXPR",
"visualization": false,
"startDate": "2018-01-20",
"endDate": "2023-01-20"
},
"regular": {
"code": "ts_rank(adv20 - volume, 15) + ts_rank(volume, 15)",
"description": null,
"operatorCount": 4
},
"dateCreated": "2025-11-14T04:02:06-05:00",
"dateSubmitted": null,
"dateModified": "2025-11-14T04:02:07-05:00",
"name": null,
"favorite": false,
"hidden": false,
"color": null,
"category": null,
"tags": [],
"classifications": [
{
"id": "DATA_USAGE:SINGLE_DATA_SET",
"name": "Single Data Set Alpha"
}
],
"grade": "INFERIOR",
"stage": "IS",
"status": "UNSUBMITTED",
"is": {
"pnl": 1607957,
"bookSize": 20000000,
"longCount": 1749,
"shortCount": 1375,
"turnover": 0.8699,
"returns": 0.0325,
"drawdown": 0.0811,
"margin": 7.5e-05,
"sharpe": 0.71,
"fitness": 0.14,
"startDate": "2018-01-20",
"checks": [
{
"name": "LOW_SHARPE",
"result": "FAIL",
"limit": 1.25,
"value": 0.71
},
{
"name": "LOW_FITNESS",
"result": "FAIL",
"limit": 1.0,
"value": 0.14
},
{
"name": "LOW_TURNOVER",
"result": "PASS",
"limit": 0.01,
"value": 0.8699
},
{
"name": "HIGH_TURNOVER",
"result": "FAIL",
"limit": 0.7,
"value": 0.8699
},
{
"name": "CONCENTRATED_WEIGHT",
"result": "PASS"
},
{
"name": "LOW_SUB_UNIVERSE_SHARPE",
"result": "PASS",
"limit": 0.31,
"value": 0.84
},
{
"name": "SELF_CORRELATION",
"result": "PENDING"
},
{
"name": "MATCHES_COMPETITION",
"result": "PASS",
"competitions": [
{
"id": "challenge",
"name": "Challenge"
}
]
}
]
},
"os": null,
"train": null,
"test": null,
"prod": null,
"competitions": null,
"themes": null,
"pyramids": null,
"pyramidThemes": null,
"team": null
}
},
{
"expression": "ts_mean(high - ts_delay(high, 1), 60) - ts_mean(low - ts_delay(low, 1), 60)",
"time_consuming": 86.01,
"formatted_time": "1分26.01秒",
"alpha_id": "wpxqw73d",
"status": "success",
"description": "/",
"simulation_timestamp": "2025-11-14 17:02:09",
"metrics": {
"id": "wpxqw73d",
"type": "REGULAR",
"author": "YC93384",
"settings": {
"instrumentType": "EQUITY",
"region": "USA",
"universe": "TOP3000",
"delay": 1,
"decay": 0,
"neutralization": "INDUSTRY",
"truncation": 0.08,
"pasteurization": "ON",
"unitHandling": "VERIFY",
"nanHandling": "OFF",
"maxTrade": "OFF",
"language": "FASTEXPR",
"visualization": false,
"startDate": "2018-01-20",
"endDate": "2023-01-20"
},
"regular": {
"code": "ts_mean(high - ts_delay(high, 1), 60) - ts_mean(low - ts_delay(low, 1), 60)",
"description": null,
"operatorCount": 7
},
"dateCreated": "2025-11-14T04:02:06-05:00",
"dateSubmitted": null,
"dateModified": "2025-11-14T04:02:06-05:00",
"name": null,
"favorite": false,
"hidden": false,
"color": null,
"category": null,
"tags": [],
"classifications": [
{
"id": "DATA_USAGE:SINGLE_DATA_SET",
"name": "Single Data Set Alpha"
}
],
"grade": "INFERIOR",
"stage": "IS",
"status": "UNSUBMITTED",
"is": {
"pnl": -1454336,
"bookSize": 20000000,
"longCount": 1602,
"shortCount": 1526,
"turnover": 1.0897,
"returns": -0.0294,
"drawdown": 0.5598,
"margin": -5.4e-05,
"sharpe": -0.19,
"fitness": -0.03,
"startDate": "2018-01-20",
"checks": [
{
"name": "LOW_SHARPE",
"result": "FAIL",
"limit": 1.25,
"value": -0.19
},
{
"name": "LOW_FITNESS",
"result": "FAIL",
"limit": 1.0,
"value": -0.03
},
{
"name": "LOW_TURNOVER",
"result": "PASS",
"limit": 0.01,
"value": 1.0897
},
{
"name": "HIGH_TURNOVER",
"result": "FAIL",
"limit": 0.7,
"value": 1.0897
},
{
"name": "CONCENTRATED_WEIGHT",
"result": "FAIL",
"date": "2022-10-27",
"limit": 0.1,
"value": 0.298634
},
{
"name": "LOW_SUB_UNIVERSE_SHARPE",
"result": "FAIL",
"limit": -0.08,
"value": -0.37
},
{
"name": "SELF_CORRELATION",
"result": "PENDING"
},
{
"name": "MATCHES_COMPETITION",
"result": "PASS",
"competitions": [
{
"id": "challenge",
"name": "Challenge"
}
]
}
]
},
"os": null,
"train": null,
"test": null,
"prod": null,
"competitions": null,
"themes": null,
"pyramids": null,
"pyramidThemes": null,
"team": null
}
}
]

@ -0,0 +1,82 @@
[
{
"expression": "ts_mean(close, 20) / ts_mean(close, 100) > 1.05 and ts_std(close / ts_mean(close, 10), 20) / ts_mean(close, 20) < 0.15",
"time_consuming": 5.94,
"formatted_time": "5.94秒",
"alpha_id": "/",
"status": "error",
"description": "Unexpected character 'a' near \"0) > 1.05 and ts_std\"",
"simulation_timestamp": "2025-11-14 17:35:28",
"metrics": null
},
{
"expression": "ts_min(low, 20) / ts_max(high, 60) > 0.8 and market_cap > ts_mean(market_cap, all)",
"time_consuming": 6.53,
"formatted_time": "6.53秒",
"alpha_id": "/",
"status": "error",
"description": "Unexpected character 'a' near \"60) > 0.8 and market\"",
"simulation_timestamp": "2025-11-14 17:35:29",
"metrics": null
},
{
"expression": "close > ts_mean(close, 50) and ts_delta(ts_rank(volume, 10), 5) > 0",
"time_consuming": 7.6,
"formatted_time": "7.60秒",
"alpha_id": "/",
"status": "error",
"description": "Unexpected character 'a' near \"lose, 50) and ts_del\"",
"simulation_timestamp": "2025-11-14 17:35:30",
"metrics": null
},
{
"expression": "ts_corr(close, vwap, 30) < 0.3 and ts_mean(volume, 5) / ts_mean(volume, 60) < 0.8",
"time_consuming": 5.8,
"formatted_time": "5.80秒",
"alpha_id": "/",
"status": "error",
"description": "Unexpected character 'a' near \"30) < 0.3 and ts_mea\"",
"simulation_timestamp": "2025-11-14 17:35:40",
"metrics": null
},
{
"expression": "abs(close - vwap) / vwap < 0.02 and volume < ts_mean(volume, 20)",
"time_consuming": 6.62,
"formatted_time": "6.62秒",
"alpha_id": "/",
"status": "error",
"description": "Unexpected character 'a' near \"ap < 0.02 and volume\"",
"simulation_timestamp": "2025-11-14 17:35:41",
"metrics": null
},
{
"expression": "(close - ts_mean(close, 30)) / ts_std(close, 30) > 1.5 and ts_delta(close, 5) < 0",
"time_consuming": 15.51,
"formatted_time": "15.51秒",
"alpha_id": "/",
"status": "error",
"description": "Unexpected character 'a' near \"30) > 1.5 and ts_del\"",
"simulation_timestamp": "2025-11-14 17:35:50",
"metrics": null
},
{
"expression": "ts_std(log(close / close[1]), 20) > ts_mean(ts_std(log(close / close[1]), 20), 60)",
"time_consuming": 1.2,
"formatted_time": "1.20秒",
"alpha_id": "/",
"status": "error",
"description": "Unexpected character '[' near \"se / close[1]), 20)\"",
"simulation_timestamp": "2025-11-14 17:35:56",
"metrics": null
},
{
"expression": "ts_range(high - low, 5) / ts_mean(high - low, 60) > 1.5 and ts_delta(ts_std(close, 10), 5) > 0",
"time_consuming": 7.38,
"formatted_time": "7.38秒",
"alpha_id": "/",
"status": "error",
"description": "Unexpected character 'a' near \"60) > 1.5 and ts_del\"",
"simulation_timestamp": "2025-11-14 17:36:02",
"metrics": null
}
]

@ -0,0 +1,12 @@
[
{
"expression": "ts_delta(ts_mean(close, 5), 10) / ts_std(close, 20) * (ts_mean(close, 20) / ts_mean(close, 100) > 1.02)",
"time_consuming": 6.62,
"formatted_time": "6.62秒",
"alpha_id": "/",
"status": "error",
"description": "Attempted to use inaccessible or unknown operator \"ts_std\"",
"simulation_timestamp": "2025-11-14 17:41:26",
"metrics": null
}
]

@ -0,0 +1,4 @@
ts_mean((close - open) / (high - low + 0.001), 20)
-ts_rank(ts_decay_linear(volume, 10), 30)
ts_rank(adv20 - volume, 15) + ts_rank(volume, 15)
ts_mean(high - ts_delay(high, 1), 60) - ts_mean(low - ts_delay(low, 1), 60)

@ -26,7 +26,7 @@ def save_results_to_file(results: List[Any], result_dir: str = 'result') -> str:
serializable_results = []
for result in results:
if hasattr(result, '__dict__'):
# 如果是dataclass对象
# 如果是dataclass对象,转换为字典
result_dict = result.__dict__.copy()
else:
# 如果是字典
@ -36,14 +36,19 @@ def save_results_to_file(results: List[Any], result_dir: str = 'result') -> str:
if 'time_consuming' in result_dict:
result_dict['time_consuming'] = round(result_dict['time_consuming'], 2)
# 处理metrics对象
for key in list(result_dict.keys()):
if hasattr(result_dict[key], '__dict__'):
result_dict[key] = result_dict[key].__dict__
# 处理浮点数精度
for metric_key, value in result_dict[key].items():
if isinstance(value, float):
result_dict[key][metric_key] = round(value, 6)
# 只需要确保所有浮点数精度一致
def round_floats(obj):
if isinstance(obj, float):
return round(obj, 6)
elif isinstance(obj, dict):
return {k: round_floats(v) for k, v in obj.items()}
elif isinstance(obj, list):
return [round_floats(item) for item in obj]
else:
return obj
# 对结果中的所有浮点数进行精度处理
result_dict = round_floats(result_dict)
serializable_results.append(result_dict)
@ -56,4 +61,24 @@ def save_results_to_file(results: List[Any], result_dir: str = 'result') -> str:
json.dump(serializable_results, f, ensure_ascii=False, indent=2)
print(f"结果已保存到 {result_name}")
return result_name
return result_name
def save_success_alpha(success_expression_list):
"""
将成功的表达式列表保存到 success.txt 文件中
如果文件不存在则创建如果存在则追加写入
"""
if not success_expression_list:
print("没有成功的表达式需要保存")
return
try:
with open('success.txt', 'a', encoding='utf-8') as f:
for expression in success_expression_list:
f.write(expression + '\n')
print(f"成功保存 {len(success_expression_list)} 个表达式到 success.txt")
except Exception as e:
print(f"保存文件时出错: {e}")

Loading…
Cancel
Save