|
|
|
@ -1,5 +1,4 @@ |
|
|
|
import os.path |
|
|
|
import os.path |
|
|
|
|
|
|
|
|
|
|
|
import httpx |
|
|
|
import httpx |
|
|
|
import json |
|
|
|
import json |
|
|
|
from httpx import BasicAuth |
|
|
|
from httpx import BasicAuth |
|
|
|
@ -15,8 +14,8 @@ class WorldQuantBrainSimulate: |
|
|
|
self.client = None |
|
|
|
self.client = None |
|
|
|
self.brain_api_url = 'https://api.worldquantbrain.com' |
|
|
|
self.brain_api_url = 'https://api.worldquantbrain.com' |
|
|
|
|
|
|
|
|
|
|
|
def load_credentials(self): |
|
|
|
|
|
|
|
"""读取本地账号密码""" |
|
|
|
"""读取本地账号密码""" |
|
|
|
|
|
|
|
def load_credentials(self): |
|
|
|
if not os.path.exists(self.credentials_file): |
|
|
|
if not os.path.exists(self.credentials_file): |
|
|
|
print("未找到 account.txt 文件") |
|
|
|
print("未找到 account.txt 文件") |
|
|
|
with open(self.credentials_file, 'w') as f: f.write("") |
|
|
|
with open(self.credentials_file, 'w') as f: f.write("") |
|
|
|
@ -27,8 +26,8 @@ class WorldQuantBrainSimulate: |
|
|
|
credentials = eval(f.read()) |
|
|
|
credentials = eval(f.read()) |
|
|
|
return credentials[0], credentials[1] |
|
|
|
return credentials[0], credentials[1] |
|
|
|
|
|
|
|
|
|
|
|
def login(self): |
|
|
|
|
|
|
|
"""登录认证""" |
|
|
|
"""登录认证""" |
|
|
|
|
|
|
|
def login(self): |
|
|
|
username, password = self.load_credentials() |
|
|
|
username, password = self.load_credentials() |
|
|
|
self.client = httpx.Client(auth=BasicAuth(username, password)) |
|
|
|
self.client = httpx.Client(auth=BasicAuth(username, password)) |
|
|
|
|
|
|
|
|
|
|
|
@ -42,8 +41,8 @@ class WorldQuantBrainSimulate: |
|
|
|
print(f"登录失败: {response.json()}") |
|
|
|
print(f"登录失败: {response.json()}") |
|
|
|
return False |
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
def simulate_alpha(self, expression, settings=None): |
|
|
|
|
|
|
|
"""模拟Alpha因子""" |
|
|
|
"""模拟Alpha因子""" |
|
|
|
|
|
|
|
def simulate_alpha(self, expression, settings=None): |
|
|
|
if self.client is None: |
|
|
|
if self.client is None: |
|
|
|
raise Exception("请先登录") |
|
|
|
raise Exception("请先登录") |
|
|
|
|
|
|
|
|
|
|
|
@ -94,9 +93,87 @@ class WorldQuantBrainSimulate: |
|
|
|
# 返回一个特殊标识,表示模拟失败 |
|
|
|
# 返回一个特殊标识,表示模拟失败 |
|
|
|
return {"status": "error", "message": result} |
|
|
|
return {"status": "error", "message": result} |
|
|
|
|
|
|
|
|
|
|
|
result = sim_progress_resp.json()["alpha"] |
|
|
|
alpha_id = sim_progress_resp.json()["alpha"] |
|
|
|
print(f"生成的Alpha ID: {result}") |
|
|
|
print(f"生成的Alpha ID: {alpha_id}") |
|
|
|
return {"status": "success", "alpha_id": result} |
|
|
|
|
|
|
|
|
|
|
|
# 获取详细的性能指标 |
|
|
|
|
|
|
|
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 == 200: |
|
|
|
|
|
|
|
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: |
|
|
|
|
|
|
|
# 基本统计信息 |
|
|
|
|
|
|
|
if 'returns' in alpha_data: |
|
|
|
|
|
|
|
returns = alpha_data['returns'] |
|
|
|
|
|
|
|
metrics.update({ |
|
|
|
|
|
|
|
'sharpe_ratio': returns.get('sharpe', None), |
|
|
|
|
|
|
|
'annual_return': returns.get('annualReturn', None), |
|
|
|
|
|
|
|
'annual_volatility': returns.get('annualVolatility', None), |
|
|
|
|
|
|
|
'max_drawdown': returns.get('maxDrawdown', None), |
|
|
|
|
|
|
|
'information_ratio': returns.get('informationRatio', None), |
|
|
|
|
|
|
|
'tail_ratio': returns.get('tailRatio', None), |
|
|
|
|
|
|
|
'common_ratio': returns.get('commonRatio', None), |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 风险调整后收益 |
|
|
|
|
|
|
|
if 'riskAdjustment' in alpha_data: |
|
|
|
|
|
|
|
risk_adj = alpha_data['riskAdjustment'] |
|
|
|
|
|
|
|
metrics.update({ |
|
|
|
|
|
|
|
'risk_adjusted_return': risk_adj.get('return', None), |
|
|
|
|
|
|
|
'turnover': risk_adj.get('turnover', None), |
|
|
|
|
|
|
|
'score': risk_adj.get('score', None), |
|
|
|
|
|
|
|
'specific_return': risk_adj.get('specificReturn', None), |
|
|
|
|
|
|
|
'specific_risk': risk_adj.get('specificRisk', None), |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 分位数表现 |
|
|
|
|
|
|
|
if 'quantiles' in alpha_data: |
|
|
|
|
|
|
|
quantiles = alpha_data['quantiles'] |
|
|
|
|
|
|
|
metrics.update({ |
|
|
|
|
|
|
|
'top_minus_bottom': quantiles.get('topMinusBottom', None), |
|
|
|
|
|
|
|
'top_decile_return': quantiles.get('topDecileReturn', None), |
|
|
|
|
|
|
|
'bottom_decile_return': quantiles.get('bottomDecileReturn', None), |
|
|
|
|
|
|
|
'ic': quantiles.get('ic', None), |
|
|
|
|
|
|
|
'ic_decay': quantiles.get('icDecay', None), |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 其他重要指标 |
|
|
|
|
|
|
|
metrics.update({ |
|
|
|
|
|
|
|
'total_return': alpha_data.get('totalReturn', None), |
|
|
|
|
|
|
|
'capacity': alpha_data.get('capacity', None), |
|
|
|
|
|
|
|
'fitness': alpha_data.get('fitness', None), |
|
|
|
|
|
|
|
'instrument_count': alpha_data.get('instrumentCount', None), |
|
|
|
|
|
|
|
'start_date': alpha_data.get('startDate', None), |
|
|
|
|
|
|
|
'end_date': alpha_data.get('endDate', None), |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
|
|
metrics['error'] = f"解析指标时出错: {str(e)}" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return metrics |
|
|
|
|
|
|
|
|
|
|
|
def close(self): |
|
|
|
def close(self): |
|
|
|
"""关闭连接""" |
|
|
|
"""关闭连接""" |
|
|
|
@ -109,8 +186,8 @@ class AlphaSimulationManager: |
|
|
|
self.credentials_file = credentials_file |
|
|
|
self.credentials_file = credentials_file |
|
|
|
self.results = [] |
|
|
|
self.results = [] |
|
|
|
|
|
|
|
|
|
|
|
def format_time(self, seconds): |
|
|
|
|
|
|
|
"""将秒数格式化为 xx分xx秒 格式""" |
|
|
|
"""将秒数格式化为 xx分xx秒 格式""" |
|
|
|
|
|
|
|
def format_time(self, seconds): |
|
|
|
if seconds < 60: |
|
|
|
if seconds < 60: |
|
|
|
return f"{seconds:.2f}秒" |
|
|
|
return f"{seconds:.2f}秒" |
|
|
|
else: |
|
|
|
else: |
|
|
|
@ -118,8 +195,8 @@ class AlphaSimulationManager: |
|
|
|
remaining_seconds = seconds % 60 |
|
|
|
remaining_seconds = seconds % 60 |
|
|
|
return f"{minutes}分{remaining_seconds:.2f}秒" |
|
|
|
return f"{minutes}分{remaining_seconds:.2f}秒" |
|
|
|
|
|
|
|
|
|
|
|
def simulate_single_alpha(self, api, expression, settings=None): |
|
|
|
|
|
|
|
"""模拟单个Alpha因子(线程安全)""" |
|
|
|
"""模拟单个Alpha因子(线程安全)""" |
|
|
|
|
|
|
|
def simulate_single_alpha(self, api, expression, settings=None): |
|
|
|
alpha_start_time = time.time() |
|
|
|
alpha_start_time = time.time() |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
try: |
|
|
|
@ -137,11 +214,49 @@ class AlphaSimulationManager: |
|
|
|
"formatted_time": self.format_time(time_consuming), |
|
|
|
"formatted_time": self.format_time(time_consuming), |
|
|
|
"alpha_id": simulation_result["alpha_id"], |
|
|
|
"alpha_id": simulation_result["alpha_id"], |
|
|
|
"status": "success", |
|
|
|
"status": "success", |
|
|
|
"description": "/" |
|
|
|
"description": "/", |
|
|
|
|
|
|
|
"simulation_timestamp": time.strftime("%Y-%m-%d %H:%M:%S"), |
|
|
|
|
|
|
|
# 性能指标 |
|
|
|
|
|
|
|
"performance_metrics": { |
|
|
|
|
|
|
|
"sharpe_ratio": simulation_result["metrics"].get('sharpe_ratio'), |
|
|
|
|
|
|
|
"annual_return": simulation_result["metrics"].get('annual_return'), |
|
|
|
|
|
|
|
"annual_volatility": simulation_result["metrics"].get('annual_volatility'), |
|
|
|
|
|
|
|
"max_drawdown": simulation_result["metrics"].get('max_drawdown'), |
|
|
|
|
|
|
|
"information_ratio": simulation_result["metrics"].get('information_ratio'), |
|
|
|
|
|
|
|
"total_return": simulation_result["metrics"].get('total_return'), |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
# 风险指标 |
|
|
|
|
|
|
|
"risk_metrics": { |
|
|
|
|
|
|
|
"turnover": simulation_result["metrics"].get('turnover'), |
|
|
|
|
|
|
|
"score": simulation_result["metrics"].get('score'), |
|
|
|
|
|
|
|
"specific_return": simulation_result["metrics"].get('specific_return'), |
|
|
|
|
|
|
|
"specific_risk": simulation_result["metrics"].get('specific_risk'), |
|
|
|
|
|
|
|
"tail_ratio": simulation_result["metrics"].get('tail_ratio'), |
|
|
|
|
|
|
|
"common_ratio": simulation_result["metrics"].get('common_ratio'), |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
# 分位数指标 |
|
|
|
|
|
|
|
"quantile_metrics": { |
|
|
|
|
|
|
|
"top_minus_bottom": simulation_result["metrics"].get('top_minus_bottom'), |
|
|
|
|
|
|
|
"top_decile_return": simulation_result["metrics"].get('top_decile_return'), |
|
|
|
|
|
|
|
"bottom_decile_return": simulation_result["metrics"].get('bottom_decile_return'), |
|
|
|
|
|
|
|
"ic": simulation_result["metrics"].get('ic'), |
|
|
|
|
|
|
|
"ic_decay": simulation_result["metrics"].get('ic_decay'), |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
# 其他指标 |
|
|
|
|
|
|
|
"other_metrics": { |
|
|
|
|
|
|
|
"capacity": simulation_result["metrics"].get('capacity'), |
|
|
|
|
|
|
|
"fitness": simulation_result["metrics"].get('fitness'), |
|
|
|
|
|
|
|
"instrument_count": simulation_result["metrics"].get('instrument_count'), |
|
|
|
|
|
|
|
"start_date": simulation_result["metrics"].get('start_date'), |
|
|
|
|
|
|
|
"end_date": simulation_result["metrics"].get('end_date'), |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
print(f"✓ 因子模拟成功: {expression}") |
|
|
|
print(f"✓ 因子模拟成功: {expression}") |
|
|
|
print(f" 耗时: {self.format_time(time_consuming)},Alpha ID: {simulation_result['alpha_id']}") |
|
|
|
print(f" 耗时: {self.format_time(time_consuming)},Alpha ID: {simulation_result['alpha_id']}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 打印关键指标 |
|
|
|
|
|
|
|
self._print_success_metrics(simulation_result["metrics"]) |
|
|
|
|
|
|
|
|
|
|
|
else: |
|
|
|
else: |
|
|
|
# 模拟失败的结果(API返回的错误) |
|
|
|
# 模拟失败的结果(API返回的错误) |
|
|
|
result = { |
|
|
|
result = { |
|
|
|
@ -150,7 +265,12 @@ class AlphaSimulationManager: |
|
|
|
"formatted_time": self.format_time(time_consuming), |
|
|
|
"formatted_time": self.format_time(time_consuming), |
|
|
|
"alpha_id": "/", |
|
|
|
"alpha_id": "/", |
|
|
|
"status": "error", |
|
|
|
"status": "error", |
|
|
|
"description": simulation_result["message"] |
|
|
|
"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"✗ 因子模拟失败: {expression}") |
|
|
|
print(f" 耗时: {self.format_time(time_consuming)},错误: {simulation_result['message']}") |
|
|
|
print(f" 耗时: {self.format_time(time_consuming)},错误: {simulation_result['message']}") |
|
|
|
@ -166,15 +286,42 @@ class AlphaSimulationManager: |
|
|
|
"formatted_time": self.format_time(time_consuming), |
|
|
|
"formatted_time": self.format_time(time_consuming), |
|
|
|
"alpha_id": "/", |
|
|
|
"alpha_id": "/", |
|
|
|
"status": "failed", |
|
|
|
"status": "failed", |
|
|
|
"description": str(e) |
|
|
|
"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"✗ 因子模拟异常: {expression}") |
|
|
|
print(f" 耗时: {self.format_time(time_consuming)},异常: {str(e)}") |
|
|
|
print(f" 耗时: {self.format_time(time_consuming)},异常: {str(e)}") |
|
|
|
|
|
|
|
|
|
|
|
return result |
|
|
|
return result |
|
|
|
|
|
|
|
|
|
|
|
def simulate_alpha_batch(self, alpha_batch, batch_number): |
|
|
|
"""打印成功因子的关键指标""" |
|
|
|
|
|
|
|
def _print_success_metrics(self, metrics): |
|
|
|
|
|
|
|
if 'error' in metrics: |
|
|
|
|
|
|
|
print(f" 指标获取错误: {metrics['error']}") |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
key_metrics = [ |
|
|
|
|
|
|
|
('夏普比率', 'sharpe_ratio'), |
|
|
|
|
|
|
|
('年化收益', 'annual_return'), |
|
|
|
|
|
|
|
('最大回撤', 'max_drawdown'), |
|
|
|
|
|
|
|
('信息比率', 'information_ratio'), |
|
|
|
|
|
|
|
('总分', 'score'), |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print(" 关键指标:") |
|
|
|
|
|
|
|
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}") |
|
|
|
|
|
|
|
|
|
|
|
"""模拟一批Alpha因子(3个一组)""" |
|
|
|
"""模拟一批Alpha因子(3个一组)""" |
|
|
|
|
|
|
|
def simulate_alpha_batch(self, alpha_batch, batch_number): |
|
|
|
print(f"\n{'=' * 60}") |
|
|
|
print(f"\n{'=' * 60}") |
|
|
|
print(f"开始第 {batch_number} 批因子模拟 (共 {len(alpha_batch)} 个因子)") |
|
|
|
print(f"开始第 {batch_number} 批因子模拟 (共 {len(alpha_batch)} 个因子)") |
|
|
|
print(f"因子列表: {alpha_batch}") |
|
|
|
print(f"因子列表: {alpha_batch}") |
|
|
|
@ -215,8 +362,8 @@ class AlphaSimulationManager: |
|
|
|
|
|
|
|
|
|
|
|
return batch_results |
|
|
|
return batch_results |
|
|
|
|
|
|
|
|
|
|
|
def run_simulation(self, alpha_list, batch_size=3): |
|
|
|
|
|
|
|
"""运行批量模拟""" |
|
|
|
"""运行批量模拟""" |
|
|
|
|
|
|
|
def run_simulation(self, alpha_list, batch_size=3): |
|
|
|
print("开始Alpha因子批量模拟...") |
|
|
|
print("开始Alpha因子批量模拟...") |
|
|
|
total_start_time = time.time() |
|
|
|
total_start_time = time.time() |
|
|
|
|
|
|
|
|
|
|
|
@ -247,8 +394,8 @@ class AlphaSimulationManager: |
|
|
|
|
|
|
|
|
|
|
|
return all_results |
|
|
|
return all_results |
|
|
|
|
|
|
|
|
|
|
|
def print_summary(self, results, total_time): |
|
|
|
|
|
|
|
"""打印结果汇总""" |
|
|
|
"""打印结果汇总""" |
|
|
|
|
|
|
|
def print_summary(self, results, total_time): |
|
|
|
print(f"\n{'=' * 60}") |
|
|
|
print(f"\n{'=' * 60}") |
|
|
|
print("模拟结果汇总") |
|
|
|
print("模拟结果汇总") |
|
|
|
print(f"{'=' * 60}") |
|
|
|
print(f"{'=' * 60}") |
|
|
|
@ -274,13 +421,21 @@ class AlphaSimulationManager: |
|
|
|
print(f" 原因: {result['description']}") |
|
|
|
print(f" 原因: {result['description']}") |
|
|
|
print() |
|
|
|
print() |
|
|
|
|
|
|
|
|
|
|
|
def save_results(self, results): |
|
|
|
|
|
|
|
"""保存结果到文件""" |
|
|
|
"""保存结果到文件""" |
|
|
|
|
|
|
|
def save_results(self, results): |
|
|
|
# 转换为可序列化的格式 |
|
|
|
# 转换为可序列化的格式 |
|
|
|
serializable_results = [] |
|
|
|
serializable_results = [] |
|
|
|
for result in results: |
|
|
|
for result in results: |
|
|
|
serializable_result = result.copy() |
|
|
|
serializable_result = result.copy() |
|
|
|
serializable_result['time_consuming'] = round(serializable_result['time_consuming'], 2) |
|
|
|
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) |
|
|
|
serializable_results.append(serializable_result) |
|
|
|
|
|
|
|
|
|
|
|
# 将日志文件, 保存到当前目录下, result 文件夹中 |
|
|
|
# 将日志文件, 保存到当前目录下, result 文件夹中 |
|
|
|
|