update
This commit is contained in:
@@ -1 +1 @@
|
|||||||
ts_Mean(ts_mean(close - delay(close,1),5) / atr(15), 30)
|
rank(ts_sum(vec_avg(nws12_afterhsz_sl), 60)) * 0.7 + rank(-ts_delta(close, 2)) * 0.3
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"simulation_info": {
|
||||||
|
"total_count": 1,
|
||||||
|
"success_count": 0,
|
||||||
|
"failed_count": 1,
|
||||||
|
"completion_time": "2025-11-13 21:58:11",
|
||||||
|
"total_time_seconds": 10.505059003829956
|
||||||
|
},
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"expression": "ts_mean(ts_mean(close - delay(close,1),5) / atr(15), 30)",
|
||||||
|
"time_consuming_seconds": 10.505059003829956,
|
||||||
|
"formatted_time": "10.51秒",
|
||||||
|
"alpha_id": "/",
|
||||||
|
"status": "failed",
|
||||||
|
"description": "'alpha'",
|
||||||
|
"simulation_timestamp": "2025-11-13 21:58:11",
|
||||||
|
"performance_metrics": {},
|
||||||
|
"risk_metrics": {},
|
||||||
|
"quantile_metrics": {},
|
||||||
|
"other_metrics": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"expression": "rank(ts_sum(vec_avg(nws12_afterhsz_sl), 60)) * 0.7 + rank(-ts_delta(close, 2)) * 0.3",
|
||||||
|
"time_consuming": 75.8,
|
||||||
|
"formatted_time": "1分15.80秒",
|
||||||
|
"alpha_id": "WjqvZQLO",
|
||||||
|
"status": "success",
|
||||||
|
"description": "/",
|
||||||
|
"simulation_timestamp": "2025-11-13 22:04:01",
|
||||||
|
"performance_metrics": {
|
||||||
|
"sharpe_ratio": null,
|
||||||
|
"annual_return": null,
|
||||||
|
"annual_volatility": null,
|
||||||
|
"max_drawdown": null,
|
||||||
|
"information_ratio": null,
|
||||||
|
"total_return": null
|
||||||
|
},
|
||||||
|
"risk_metrics": {
|
||||||
|
"turnover": null,
|
||||||
|
"score": null,
|
||||||
|
"specific_return": null,
|
||||||
|
"specific_risk": null,
|
||||||
|
"tail_ratio": null,
|
||||||
|
"common_ratio": null
|
||||||
|
},
|
||||||
|
"quantile_metrics": {
|
||||||
|
"top_minus_bottom": null,
|
||||||
|
"top_decile_return": null,
|
||||||
|
"bottom_decile_return": null,
|
||||||
|
"ic": null,
|
||||||
|
"ic_decay": null
|
||||||
|
},
|
||||||
|
"other_metrics": {
|
||||||
|
"capacity": null,
|
||||||
|
"fitness": null,
|
||||||
|
"instrument_count": null,
|
||||||
|
"start_date": null,
|
||||||
|
"end_date": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"expression": "rank(ts_sum(vec_avg(nws12_afterhsz_sl), 60)) * 0.7 + rank(-ts_delta(close, 2)) * 0.3",
|
||||||
|
"time_consuming": 78.3,
|
||||||
|
"formatted_time": "1分18.30秒",
|
||||||
|
"alpha_id": "WjqvZQLO",
|
||||||
|
"status": "success",
|
||||||
|
"description": "/",
|
||||||
|
"simulation_timestamp": "2025-11-13 22:08:12",
|
||||||
|
"performance_metrics": {
|
||||||
|
"sharpe_ratio": null,
|
||||||
|
"annual_return": null,
|
||||||
|
"annual_volatility": null,
|
||||||
|
"max_drawdown": null,
|
||||||
|
"information_ratio": null,
|
||||||
|
"total_return": null
|
||||||
|
},
|
||||||
|
"risk_metrics": {
|
||||||
|
"turnover": null,
|
||||||
|
"score": null,
|
||||||
|
"specific_return": null,
|
||||||
|
"specific_risk": null,
|
||||||
|
"tail_ratio": null,
|
||||||
|
"common_ratio": null
|
||||||
|
},
|
||||||
|
"quantile_metrics": {
|
||||||
|
"top_minus_bottom": null,
|
||||||
|
"top_decile_return": null,
|
||||||
|
"bottom_decile_return": null,
|
||||||
|
"ic": null,
|
||||||
|
"ic_decay": null
|
||||||
|
},
|
||||||
|
"other_metrics": {
|
||||||
|
"capacity": null,
|
||||||
|
"fitness": null,
|
||||||
|
"instrument_count": null,
|
||||||
|
"start_date": null,
|
||||||
|
"end_date": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
+171
-16
@@ -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 文件夹中
|
||||||
|
|||||||
Reference in New Issue
Block a user