You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
7.0 KiB
239 lines
7.0 KiB
# -*- coding: utf-8 -*-
|
|
"""
|
|
批量隐藏低质量Alpha
|
|
目标URL: https://api.worldquantbrain.com/users/self/alphas?limit=22&offset=0&status=UNSUBMITTED%1FIS_FAIL&is.sharpe%3C0.7&is.sharpe%3E-0.8&is.turnover%3C0.2&order=-is.sharpe&hidden=false
|
|
隐藏接口: PATCH https://api.worldquantbrain.com/alphas/{alpha_id}
|
|
Payload: {"hidden":true}
|
|
"""
|
|
import random
|
|
import time
|
|
|
|
import httpx
|
|
from httpx import BasicAuth
|
|
|
|
# 全局配置
|
|
TIMEOUT = 10.0 # 请求超时时间(秒)
|
|
MAX_RETRIES = 3 # 最大重试次数
|
|
RETRY_DELAY_MIN = 3 # 重试最小等待时间(秒)
|
|
RETRY_DELAY_MAX = 5 # 重试最大等待时间(秒)
|
|
MAX_LIMIT = 100 # 每页最大数量
|
|
MAX_PAGE = 5 # 最大页数
|
|
|
|
|
|
def login():
|
|
"""登录WorldQuant Brain API"""
|
|
# 从nacos获取账号密码
|
|
nacos_resp = httpx.get('http://192.168.31.41:30848/nacos/v1/cs/configs?dataId=wq_account&group=quantify')
|
|
if nacos_resp.status_code != 200:
|
|
print('获取账号密码失败')
|
|
return False
|
|
|
|
config = nacos_resp.json()
|
|
|
|
username = config['user_name']
|
|
password = config['password']
|
|
|
|
print(f"正在登录账户: {username}")
|
|
|
|
# 创建客户端并认证,设置超时
|
|
client = httpx.Client(auth=BasicAuth(username, password), timeout=TIMEOUT)
|
|
|
|
# 发送登录请求
|
|
response = client.post('https://api.worldquantbrain.com/authentication')
|
|
print(f"登录状态: {response.status_code}")
|
|
|
|
if response.status_code == 201:
|
|
print("登录成功!")
|
|
print(response.json())
|
|
return client
|
|
else:
|
|
print(f"登录失败: {response.json()}")
|
|
client.close()
|
|
return None
|
|
|
|
|
|
def request_with_retry(client, method, url, **kwargs):
|
|
"""
|
|
带重试机制的请求函数
|
|
默认重试3次,每次等待3-5秒
|
|
"""
|
|
for attempt in range(1, MAX_RETRIES + 1):
|
|
try:
|
|
print(f" 请求尝试 {attempt}/{MAX_RETRIES}: {method.upper()} {url}")
|
|
response = client.request(method, url, **kwargs)
|
|
return response
|
|
except Exception as e:
|
|
print(f" 请求异常: {str(e)}")
|
|
if attempt < MAX_RETRIES:
|
|
sleep_time = random.uniform(RETRY_DELAY_MIN, RETRY_DELAY_MAX)
|
|
print(f" 等待 {sleep_time:.2f} 秒后重试...")
|
|
time.sleep(sleep_time)
|
|
else:
|
|
print(f" 已达到最大重试次数 {MAX_RETRIES},放弃请求")
|
|
raise
|
|
return None
|
|
|
|
|
|
def fetch_all_alphas(client, base_url):
|
|
"""
|
|
分页获取所有符合条件的alpha
|
|
返回alpha信息列表(包含id和is数据)
|
|
使用for循环,步进MAX_LIMIT,最多获取MAX_PAGE页
|
|
"""
|
|
alphas = []
|
|
|
|
for page in range(MAX_PAGE):
|
|
# 计算当前页的offset
|
|
offset = page * MAX_LIMIT
|
|
|
|
# 构建当前页的URL
|
|
url = f"{base_url}&offset={offset}"
|
|
|
|
print(f"\n正在获取第 {page + 1}/{MAX_PAGE} 页,offset={offset} 的数据...")
|
|
|
|
try:
|
|
response = request_with_retry(client, 'get', url)
|
|
except Exception as e:
|
|
print(f"获取数据失败: {str(e)}")
|
|
break
|
|
|
|
if response.status_code != 200:
|
|
print(f"获取数据失败: {response.status_code}")
|
|
print(f"响应: {response.text}")
|
|
break
|
|
|
|
data = response.json()
|
|
results = data.get('results', [])
|
|
|
|
# 如果没有结果,说明已经获取完毕
|
|
if not results:
|
|
print("\n没有更多数据,获取完成")
|
|
break
|
|
|
|
# 提取当前页的alpha信息
|
|
for alpha in results:
|
|
alpha_info = {
|
|
'id': alpha.get('id'),
|
|
'is': alpha.get('is', {})
|
|
}
|
|
if alpha_info['id']:
|
|
alphas.append(alpha_info)
|
|
print(f" 发现Alpha: {alpha_info['id']}")
|
|
|
|
print(f"本页获取完成,共 {len(results)} 个Alpha")
|
|
|
|
sleep_time = random.uniform(3, 5)
|
|
print(f"等待 {sleep_time:.2f} 秒后继续获取下一页数据...")
|
|
time.sleep(sleep_time)
|
|
|
|
return alphas
|
|
|
|
|
|
def hide_alpha(client, alpha_info):
|
|
"""
|
|
隐藏单个Alpha
|
|
PATCH https://api.worldquantbrain.com/alphas/{alpha_id}
|
|
Payload: {"hidden":true}
|
|
隐藏后输出is数据
|
|
"""
|
|
alpha_id = alpha_info['id']
|
|
is_data = alpha_info.get('is', {})
|
|
|
|
url = f"https://api.worldquantbrain.com/alphas/{alpha_id}"
|
|
payload = {"hidden": True}
|
|
|
|
try:
|
|
response = request_with_retry(client, 'patch', url, json=payload)
|
|
|
|
if response.status_code in [200, 204]:
|
|
# 输出is数据
|
|
sharpe = is_data.get('sharpe', 'N/A')
|
|
fitness = is_data.get('fitness', 'N/A')
|
|
margin = is_data.get('margin', 'N/A')
|
|
drawdown = is_data.get('drawdown', 'N/A')
|
|
returns = is_data.get('returns', 'N/A')
|
|
|
|
print(f" ✓ Alpha {alpha_id} 隐藏成功")
|
|
print(f" sharpe={sharpe}, fitness={fitness}, margin={margin}, drawdown={drawdown}, returns={returns}")
|
|
return True
|
|
else:
|
|
print(f" ✗ Alpha {alpha_id} 隐藏失败: {response.status_code}")
|
|
print(f" 响应: {response.text}")
|
|
return False
|
|
except Exception as e:
|
|
print(f" ✗ Alpha {alpha_id} 隐藏异常: {str(e)}")
|
|
return False
|
|
|
|
|
|
def batch_hide_alphas(client, alphas):
|
|
"""
|
|
批量隐藏Alpha
|
|
"""
|
|
total = len(alphas)
|
|
success_count = 0
|
|
fail_count = 0
|
|
|
|
print(f"\n开始批量隐藏 {total} 个Alpha...")
|
|
print("=" * 50)
|
|
|
|
for index, alpha_info in enumerate(alphas, 1):
|
|
alpha_id = alpha_info['id']
|
|
print(f"[{index}/{total}] 正在隐藏 Alpha: {alpha_id}")
|
|
|
|
if hide_alpha(client, alpha_info):
|
|
success_count += 1
|
|
else:
|
|
fail_count += 1
|
|
|
|
time.sleep(0.5)
|
|
|
|
print("=" * 50)
|
|
print(f"批量隐藏完成!")
|
|
print(f"成功: {success_count} 个")
|
|
print(f"失败: {fail_count} 个")
|
|
|
|
return success_count, fail_count
|
|
|
|
|
|
def run(client):
|
|
# 目标URL(获取未隐藏的、低sharpe的alpha)
|
|
TARGET_URL = "https://api.worldquantbrain.com/users/self/alphas?limit=100&offset=0&status=UNSUBMITTED%1FIS_FAIL&is.sharpe%3C0.65&is.sharpe%3E-0.8&is.turnover%3C0.2&order=-is.sharpe&hidden=false"
|
|
|
|
if client:
|
|
try:
|
|
print("\n" + "=" * 50)
|
|
print("获取所有符合条件的Alpha")
|
|
print("=" * 50)
|
|
|
|
alphas = fetch_all_alphas(client, TARGET_URL)
|
|
|
|
if not alphas:
|
|
print("没有找到需要隐藏的Alpha")
|
|
exit(1)
|
|
else:
|
|
print(f"\n总共找到 {len(alphas)} 个需要隐藏的Alpha")
|
|
|
|
print("\n" + "=" * 50)
|
|
print("批量隐藏Alpha")
|
|
print("=" * 50)
|
|
|
|
success, fail = batch_hide_alphas(client, alphas)
|
|
|
|
except Exception as e:
|
|
print(str(e))
|
|
else:
|
|
print("登录失败,程序退出")
|
|
|
|
|
|
def main():
|
|
# 登录
|
|
client = login()
|
|
|
|
while True:
|
|
run(client)
|
|
time.sleep(60)
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
|