parent
0b84cb8222
commit
d4e55e9aca
@ -1,25 +0,0 @@ |
||||
|
||||
### 依赖 |
||||
pip install httpx |
||||
|
||||
### 目录结构 |
||||
|
||||
```text |
||||
FactorSimulator/ |
||||
├── __init__.py # 包初始化文件,定义包级别的导入和元数据 |
||||
├── main.py # 程序主入口,负责启动批量模拟流程 |
||||
├── core/ # 核心业务逻辑模块 |
||||
│ ├── __init__.py # 核心模块初始化,定义模块级别的导入 |
||||
│ ├── api_client.py # WorldQuant Brain API客户端封装,处理HTTP请求和认证 |
||||
│ └── models.py # 数据模型定义,使用dataclass定义各种指标和结果的数据结构 |
||||
├── managers/ # 管理器模块,负责业务流程协调 |
||||
│ ├── __init__.py # 管理器模块初始化 |
||||
│ └── simulation_manager.py # 模拟管理器,负责批量模拟的调度、线程池管理和结果汇总 |
||||
├── utils/ # 工具函数模块 |
||||
│ ├── __init__.py # 工具模块初始化 |
||||
│ ├── file_utils.py # 文件操作工具,处理因子列表加载和结果保存 |
||||
│ └── time_utils.py # 时间格式化工具,将秒数转换为可读格式 |
||||
└── config/ # 配置模块 |
||||
├── __init__.py # 配置模块初始化 |
||||
└── settings.py # 模拟参数配置,定义默认的模拟设置常量 |
||||
``` |
||||
@ -1,13 +0,0 @@ |
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
WorldQuant Brain 因子模拟器 |
||||
用于批量模拟Alpha因子的工具 |
||||
""" |
||||
|
||||
__version__ = "0.0.1" |
||||
__author__ = "Jack" |
||||
|
||||
from .core.api_client import WorldQuantBrainSimulate |
||||
from .managers.simulation_manager import AlphaSimulationManager |
||||
|
||||
__all__ = ['WorldQuantBrainSimulate', 'AlphaSimulationManager'] |
||||
@ -1 +0,0 @@ |
||||
ts_delta(ts_mean(close, 5), 10) / ts_std(close, 20) * (ts_mean(close, 20) / ts_mean(close, 100) > 1.02) |
||||
@ -1,8 +0,0 @@ |
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
配置模块 - 包含配置常量 |
||||
""" |
||||
|
||||
from .settings import DEFAULT_SIMULATION_SETTINGS |
||||
|
||||
__all__ = ['DEFAULT_SIMULATION_SETTINGS'] |
||||
@ -1,19 +1,53 @@ |
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
模拟配置常量 |
||||
""" |
||||
|
||||
DEFAULT_SIMULATION_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, |
||||
} |
||||
"""配置文件""" |
||||
|
||||
import os |
||||
from typing import Dict, Any |
||||
|
||||
|
||||
class Settings: |
||||
"""应用配置""" |
||||
|
||||
# 数据库配置 |
||||
DATABASE_CONFIG = { |
||||
"host": "localhost", |
||||
"port": "5432", |
||||
"user": "jack", |
||||
"password": "aaaAAA111", |
||||
"database": "alpha" |
||||
} |
||||
|
||||
# API配置 |
||||
BRAIN_API_URL = "https://api.worldquantbrain.com" |
||||
|
||||
# 模拟配置 |
||||
SIMULATION_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, |
||||
} |
||||
|
||||
# 批处理配置 |
||||
BATCH_SIZE = 3 |
||||
CHECK_INTERVAL = 300 # 5分钟 |
||||
TOKEN_REFRESH_THRESHOLD = 1800 # 30分钟 |
||||
|
||||
# 通知配置 |
||||
GOTIFY_URL = "https://gotify.erhe.top/message?token=AvKJCJwQKU6yLP8" |
||||
|
||||
@property |
||||
def credentials_file(self) -> str: |
||||
"""获取凭证文件路径""" |
||||
return os.path.join(os.path.dirname(os.path.dirname(__file__)), 'account.txt') |
||||
|
||||
|
||||
settings = Settings() |
||||
@ -1,9 +0,0 @@ |
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
核心模块 - 包含API客户端和数据模型 |
||||
""" |
||||
|
||||
from .api_client import WorldQuantBrainSimulate |
||||
from .models import AlphaMetrics, SimulationResult |
||||
|
||||
__all__ = ['WorldQuantBrainSimulate', 'AlphaMetrics', 'SimulationResult'] |
||||
@ -1,158 +0,0 @@ |
||||
# -*- coding: utf-8 -*- |
||||
import os.path |
||||
import httpx |
||||
import time |
||||
from httpx import BasicAuth |
||||
from typing import Dict, Any, Optional, Tuple |
||||
|
||||
|
||||
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) -> Tuple[str, str]: |
||||
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) -> bool: |
||||
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("登录成功!") |
||||
print(f"账户信息: {response.json()}") |
||||
return True |
||||
else: |
||||
print(f"登录失败: {response.json()}") |
||||
return False |
||||
|
||||
"""模拟Alpha因子""" |
||||
def simulate_alpha(self, expression: str, settings: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: |
||||
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 |
||||
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) |
||||
|
||||
# 如果因子模拟不通过, 获取一下失败信息 |
||||
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: str) -> Dict[str, Any]: |
||||
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() |
||||
|
||||
# 以后可能需要获取其他参数 |
||||
if alpha_data.get('metrics'): |
||||
alpha_data = alpha_data.get('metrics') |
||||
|
||||
return alpha_data or {} |
||||
else: |
||||
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 { |
||||
"train": {}, |
||||
"is": {}, |
||||
"test": {}, |
||||
"grade": None, |
||||
"stage": None, |
||||
"status": None, |
||||
"dateCreated": None, |
||||
"id": alpha_id |
||||
} |
||||
|
||||
def close(self): |
||||
"""关闭连接""" |
||||
if self.client: |
||||
self.client.close() |
||||
@ -0,0 +1,176 @@ |
||||
# -*- coding: utf-8 -*- |
||||
"""数据库管理层""" |
||||
|
||||
import psycopg2 |
||||
from typing import List, Optional |
||||
from config.settings import settings |
||||
from models.entities import SimulationResult, AlphaExpression |
||||
|
||||
|
||||
class DatabaseManager: |
||||
"""数据库管理类""" |
||||
|
||||
def __init__(self): |
||||
self.connection = None |
||||
self.init_database() |
||||
|
||||
def create_database(self) -> None: |
||||
"""创建数据库(如果不存在)""" |
||||
try: |
||||
# 先连接到默认的postgres数据库来创建alpha数据库 |
||||
conn = psycopg2.connect( |
||||
host=settings.DATABASE_CONFIG["host"], |
||||
port=settings.DATABASE_CONFIG["port"], |
||||
database="postgres", |
||||
user=settings.DATABASE_CONFIG["user"], |
||||
password=settings.DATABASE_CONFIG["password"] |
||||
) |
||||
conn.autocommit = True |
||||
cursor = conn.cursor() |
||||
|
||||
# 检查数据库是否存在 |
||||
cursor.execute("SELECT 1 FROM pg_catalog.pg_database WHERE datname = %s", |
||||
(settings.DATABASE_CONFIG["database"],)) |
||||
exists = cursor.fetchone() |
||||
|
||||
if not exists: |
||||
cursor.execute(f"CREATE DATABASE {settings.DATABASE_CONFIG['database']}") |
||||
print(f"数据库 {settings.DATABASE_CONFIG['database']} 创建成功") |
||||
else: |
||||
print(f"数据库 {settings.DATABASE_CONFIG['database']} 已存在") |
||||
|
||||
cursor.close() |
||||
conn.close() |
||||
|
||||
except Exception as e: |
||||
print(f"创建数据库时出错: {e}") |
||||
raise |
||||
|
||||
def get_connection(self) -> psycopg2.extensions.connection: |
||||
"""获取数据库连接""" |
||||
if self.connection is None or self.connection.closed: |
||||
self.connection = psycopg2.connect( |
||||
host=settings.DATABASE_CONFIG["host"], |
||||
port=settings.DATABASE_CONFIG["port"], |
||||
database=settings.DATABASE_CONFIG["database"], |
||||
user=settings.DATABASE_CONFIG["user"], |
||||
password=settings.DATABASE_CONFIG["password"] |
||||
) |
||||
return self.connection |
||||
|
||||
def init_database(self) -> None: |
||||
"""初始化数据库和表结构""" |
||||
# 先创建数据库 |
||||
self.create_database() |
||||
|
||||
# 然后连接到此数据库创建表 |
||||
conn = self.get_connection() |
||||
cursor = conn.cursor() |
||||
|
||||
# 创建 alpha_prepare 表 |
||||
cursor.execute(''' |
||||
CREATE TABLE IF NOT EXISTS alpha_prepare |
||||
( |
||||
id |
||||
SERIAL |
||||
PRIMARY |
||||
KEY, |
||||
alpha |
||||
TEXT |
||||
NOT |
||||
NULL |
||||
UNIQUE, |
||||
unused |
||||
BOOLEAN |
||||
NOT |
||||
NULL |
||||
DEFAULT |
||||
TRUE, |
||||
created_time |
||||
TIMESTAMP |
||||
DEFAULT |
||||
CURRENT_TIMESTAMP |
||||
) |
||||
''') |
||||
|
||||
# 创建 simulation 表 |
||||
cursor.execute(''' |
||||
CREATE TABLE IF NOT EXISTS simulation |
||||
( |
||||
id |
||||
SERIAL |
||||
PRIMARY |
||||
KEY, |
||||
expression |
||||
TEXT |
||||
NOT |
||||
NULL, |
||||
time_consuming |
||||
REAL |
||||
NOT |
||||
NULL, |
||||
status |
||||
TEXT |
||||
NOT |
||||
NULL, |
||||
timestamp |
||||
TEXT |
||||
NOT |
||||
NULL, |
||||
alpha_id |
||||
TEXT, |
||||
message |
||||
TEXT, |
||||
created_time |
||||
TIMESTAMP |
||||
DEFAULT |
||||
CURRENT_TIMESTAMP |
||||
) |
||||
''') |
||||
|
||||
conn.commit() |
||||
print(f"数据库 {settings.DATABASE_CONFIG['database']} 表结构初始化完成") |
||||
|
||||
def get_unused_alpha(self) -> List[str]: |
||||
"""获取所有未使用的alpha表达式""" |
||||
conn = self.get_connection() |
||||
cursor = conn.cursor() |
||||
|
||||
cursor.execute("SELECT alpha FROM alpha_prepare WHERE unused = TRUE") |
||||
results = cursor.fetchall() |
||||
|
||||
alpha_list = [result[0] for result in results] |
||||
return alpha_list |
||||
|
||||
def mark_alpha_used(self, alpha: str) -> None: |
||||
"""将alpha标记为已使用""" |
||||
conn = self.get_connection() |
||||
cursor = conn.cursor() |
||||
|
||||
cursor.execute("UPDATE alpha_prepare SET unused = FALSE WHERE alpha = %s", (alpha,)) |
||||
conn.commit() |
||||
|
||||
def insert_simulation_result(self, result: SimulationResult) -> None: |
||||
"""插入模拟结果到simulation表""" |
||||
conn = self.get_connection() |
||||
cursor = conn.cursor() |
||||
|
||||
cursor.execute(''' |
||||
INSERT INTO simulation |
||||
(expression, time_consuming, status, timestamp, alpha_id, message) |
||||
VALUES (%s, %s, %s, %s, %s, %s) |
||||
''', ( |
||||
result.expression, |
||||
result.time_consuming, |
||||
result.status, |
||||
result.timestamp, |
||||
result.alpha_id, |
||||
result.message or "" |
||||
)) |
||||
|
||||
conn.commit() |
||||
|
||||
def close_connection(self) -> None: |
||||
"""关闭数据库连接""" |
||||
if self.connection and not self.connection.closed: |
||||
self.connection.close() |
||||
@ -1,62 +0,0 @@ |
||||
# -*- coding: utf-8 -*- |
||||
from dataclasses import dataclass |
||||
from typing import Dict, Any, Optional |
||||
|
||||
|
||||
@dataclass |
||||
class TrainMetrics: |
||||
"""训练集指标""" |
||||
sharpe_ratio: Optional[float] = None |
||||
annual_return: Optional[float] = None |
||||
max_drawdown: Optional[float] = None |
||||
turnover: Optional[float] = None |
||||
fitness: Optional[float] = None |
||||
pnl: Optional[float] = None |
||||
book_size: Optional[float] = None |
||||
long_count: Optional[float] = None |
||||
short_count: Optional[float] = None |
||||
margin: Optional[float] = None |
||||
|
||||
|
||||
@dataclass |
||||
class TestMetrics: |
||||
"""测试集指标""" |
||||
sharpe_ratio: Optional[float] = None |
||||
annual_return: Optional[float] = None |
||||
max_drawdown: Optional[float] = None |
||||
turnover: Optional[float] = None |
||||
fitness: Optional[float] = None |
||||
pnl: Optional[float] = None |
||||
|
||||
|
||||
@dataclass |
||||
class AlphaInfo: |
||||
"""Alpha基本信息""" |
||||
grade: Optional[str] = None |
||||
stage: Optional[str] = None |
||||
status: Optional[str] = None |
||||
date_created: Optional[str] = None |
||||
checks: Optional[Dict[str, Any]] = None |
||||
|
||||
|
||||
@dataclass |
||||
class AlphaMetrics: |
||||
"""Alpha因子完整指标""" |
||||
train_metrics: TrainMetrics |
||||
is_metrics: TestMetrics |
||||
test_metrics: TestMetrics |
||||
alpha_info: AlphaInfo |
||||
alpha_id: Optional[str] = None |
||||
|
||||
|
||||
@dataclass |
||||
class SimulationResult: |
||||
"""模拟结果""" |
||||
expression: str |
||||
time_consuming: float |
||||
formatted_time: str |
||||
alpha_id: str |
||||
status: str |
||||
description: str |
||||
simulation_timestamp: str |
||||
metrics: Optional[Dict[str, Any]] = None |
||||
@ -0,0 +1,126 @@ |
||||
# -*- coding: utf-8 -*- |
||||
"""Alpha模拟器核心类""" |
||||
|
||||
import time |
||||
import httpx |
||||
from datetime import datetime |
||||
from typing import List, Tuple |
||||
from config.settings import settings |
||||
from models.entities import SimulationResult, TokenInfo |
||||
from core.database import DatabaseManager |
||||
from services.auth_service import AuthService |
||||
from services.alpha_service import AlphaService |
||||
from services.notification_service import NotificationService |
||||
|
||||
|
||||
class AlphaSimulator: |
||||
"""Alpha模拟器主类""" |
||||
|
||||
def __init__(self): |
||||
self.db_manager = DatabaseManager() |
||||
self.auth_service = AuthService() |
||||
self.client = None |
||||
self.token_info = None |
||||
self.alpha_service = None |
||||
|
||||
def __del__(self): |
||||
"""析构函数,确保数据库连接被关闭""" |
||||
if hasattr(self, 'db_manager'): |
||||
self.db_manager.close_connection() |
||||
|
||||
def initialize(self) -> None: |
||||
"""初始化模拟器""" |
||||
self.client = httpx.Client() |
||||
self.login() |
||||
|
||||
def login(self) -> TokenInfo: |
||||
"""登录并初始化alpha服务""" |
||||
self.token_info = self.auth_service.login(self.client) |
||||
self.alpha_service = AlphaService(self.client) |
||||
return self.token_info |
||||
|
||||
def needs_token_refresh(self) -> bool: |
||||
"""检查是否需要刷新token""" |
||||
if not self.token_info: |
||||
return True |
||||
return self.token_info.expiry < settings.TOKEN_REFRESH_THRESHOLD |
||||
|
||||
def load_alpha_list(self) -> List[str]: |
||||
"""从数据库加载未使用的alpha表达式""" |
||||
return self.db_manager.get_unused_alpha() |
||||
|
||||
def run_batch_simulation(self, alpha_list: List[str]) -> Tuple[int, int]: |
||||
"""运行批量模拟""" |
||||
success_count = 0 |
||||
fail_count = 0 |
||||
|
||||
for i in range(0, len(alpha_list), settings.BATCH_SIZE): |
||||
batch = alpha_list[i:i + settings.BATCH_SIZE] |
||||
print(f"\n开始处理第 {i // settings.BATCH_SIZE + 1} 批因子,共 {len(batch)} 个") |
||||
|
||||
for expression in batch: |
||||
result = self._simulate_single_alpha(expression) |
||||
if result.status == "ok": |
||||
success_count += 1 |
||||
else: |
||||
fail_count += 1 |
||||
|
||||
print(f"第 {i // settings.BATCH_SIZE + 1} 批处理完成") |
||||
|
||||
self._print_summary(success_count, fail_count) |
||||
return success_count, fail_count |
||||
|
||||
def _simulate_single_alpha(self, expression: str) -> SimulationResult: |
||||
"""模拟单个Alpha表达式""" |
||||
print(f"\n模拟因子: {expression}") |
||||
start_time = time.time() |
||||
|
||||
try: |
||||
result = self.alpha_service.simulate_alpha(expression) |
||||
end_time = time.time() |
||||
time_consuming = round(end_time - start_time, 2) |
||||
|
||||
simulation_result = SimulationResult( |
||||
expression=expression, |
||||
time_consuming=time_consuming, |
||||
status=result["status"], |
||||
timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), |
||||
alpha_id=result.get("alpha_id"), |
||||
message=result.get("message", "") |
||||
) |
||||
|
||||
if result["status"] == "ok": |
||||
print(f"✅ 模拟成功 - Alpha ID: {result['alpha_id']} - 耗时: {time_consuming}秒") |
||||
else: |
||||
print(f"❌ 模拟失败 - {result.get('message', '未知错误')}") |
||||
|
||||
except Exception as e: |
||||
end_time = time.time() |
||||
time_consuming = round(end_time - start_time, 2) |
||||
simulation_result = SimulationResult( |
||||
expression=expression, |
||||
time_consuming=time_consuming, |
||||
status="err", |
||||
message=str(e), |
||||
timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
||||
) |
||||
print(f"❌ 模拟异常 - {str(e)}") |
||||
|
||||
# 保存结果并标记为已使用 |
||||
self._save_simulation_result(simulation_result) |
||||
return simulation_result |
||||
|
||||
def _save_simulation_result(self, result: SimulationResult) -> None: |
||||
"""保存模拟结果到数据库""" |
||||
self.db_manager.mark_alpha_used(result.expression) |
||||
self.db_manager.insert_simulation_result(result) |
||||
|
||||
def _print_summary(self, success_count: int, fail_count: int) -> None: |
||||
"""打印总结信息""" |
||||
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') |
||||
print(f"\n总计: 成功 {success_count} 个, 失败 {fail_count} 个") |
||||
print(f"完成时间: {now}") |
||||
print(f"所有结果已保存到 PostgreSQL 数据库 {settings.DATABASE_CONFIG['database']} 的 simulation 表中") |
||||
|
||||
# 发送通知 |
||||
NotificationService.send_to_gotify(success_count, fail_count) |
||||
@ -1,21 +1,45 @@ |
||||
# -*- coding: utf-8 -*- |
||||
import os |
||||
from managers.simulation_manager import AlphaSimulationManager |
||||
from utils.file_utils import load_alpha_list |
||||
"""主程序入口""" |
||||
|
||||
import time |
||||
from core.simulator import AlphaSimulator |
||||
from config.settings import settings |
||||
from utils.helpers import retry_on_exception |
||||
|
||||
def main(): |
||||
"""主程序入口""" |
||||
# 待模拟因子列表 |
||||
alpha_list = load_alpha_list('alpha.txt') |
||||
|
||||
@retry_on_exception(max_retries=3, delay=5.0) |
||||
def main_loop(simulator: AlphaSimulator) -> None: |
||||
"""主循环""" |
||||
if simulator.needs_token_refresh(): |
||||
print("Token需要刷新,重新登录...") |
||||
simulator.login() |
||||
|
||||
alpha_list = simulator.load_alpha_list() |
||||
if not alpha_list: |
||||
print("未找到有效的因子表达式,请检查 alpha.txt 文件") |
||||
print("暂无待处理的alpha表达式,10分钟后重新检查...") |
||||
time.sleep(600) |
||||
return |
||||
|
||||
# 创建模拟管理器并运行 |
||||
manager = AlphaSimulationManager() |
||||
results = manager.run_simulation(alpha_list, batch_size=3) |
||||
print(f"共加载 {len(alpha_list)} 个需要模拟的因子表达式") |
||||
success_count, fail_count = simulator.run_batch_simulation(alpha_list) |
||||
print(f"本轮处理完成: 成功 {success_count} 个, 失败 {fail_count} 个") |
||||
|
||||
|
||||
def main(): |
||||
"""主函数""" |
||||
simulator = AlphaSimulator() |
||||
simulator.initialize() |
||||
|
||||
try: |
||||
while True: |
||||
main_loop(simulator) |
||||
print(f"等待{settings.CHECK_INTERVAL // 60}分钟后继续检查...") |
||||
time.sleep(settings.CHECK_INTERVAL) |
||||
except KeyboardInterrupt: |
||||
print("\n程序被用户中断") |
||||
except Exception as e: |
||||
print(f"程序执行异常: {e}") |
||||
raise |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
|
||||
@ -1,8 +0,0 @@ |
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
管理模块 - 包含各种管理器类 |
||||
""" |
||||
|
||||
from .simulation_manager import AlphaSimulationManager |
||||
|
||||
__all__ = ['AlphaSimulationManager'] |
||||
@ -1,232 +0,0 @@ |
||||
# -*- coding: utf-8 -*- |
||||
import time |
||||
import json |
||||
import os |
||||
from concurrent.futures import ThreadPoolExecutor, as_completed |
||||
from random import uniform |
||||
from typing import List, Dict, Any |
||||
|
||||
from core.api_client import WorldQuantBrainSimulate |
||||
from core.models import SimulationResult |
||||
from utils.time_utils import format_time |
||||
from utils.file_utils import save_results_to_file, save_success_alpha |
||||
|
||||
|
||||
class AlphaSimulationManager: |
||||
def __init__(self, credentials_file='account.txt'): |
||||
self.credentials_file = credentials_file |
||||
self.results = [] |
||||
|
||||
"""模拟单个Alpha因子(线程安全)""" |
||||
def simulate_single_alpha(self, api: WorldQuantBrainSimulate, expression: str, |
||||
settings: Dict[str, Any] = None) -> SimulationResult: |
||||
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": |
||||
# 模拟成功的结果 - 直接使用原始metrics数据 |
||||
metrics = simulation_result["metrics"] |
||||
result = SimulationResult( |
||||
expression=expression, |
||||
time_consuming=time_consuming, |
||||
formatted_time=format_time(time_consuming), |
||||
alpha_id=simulation_result["alpha_id"], |
||||
status="success", |
||||
description="/", |
||||
simulation_timestamp=time.strftime("%Y-%m-%d %H:%M:%S"), |
||||
metrics=metrics # 直接存储原始metrics数据 |
||||
) |
||||
print(f"✓ 因子模拟成功: {expression}") |
||||
print(f" 耗时: {format_time(time_consuming)},Alpha ID: {simulation_result['alpha_id']}") |
||||
|
||||
# 打印关键指标 |
||||
self._print_success_metrics(metrics) |
||||
|
||||
else: |
||||
# 模拟失败的结果(API返回的错误) |
||||
result = SimulationResult( |
||||
expression=expression, |
||||
time_consuming=time_consuming, |
||||
formatted_time=format_time(time_consuming), |
||||
alpha_id="/", |
||||
status="error", |
||||
description=simulation_result["message"], |
||||
simulation_timestamp=time.strftime("%Y-%m-%d %H:%M:%S"), |
||||
metrics=None |
||||
) |
||||
print(f"✗ 因子模拟失败: {expression}") |
||||
print(f" 耗时: {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 = SimulationResult( |
||||
expression=expression, |
||||
time_consuming=time_consuming, |
||||
formatted_time=format_time(time_consuming), |
||||
alpha_id="/", |
||||
status="failed", |
||||
description=str(e), |
||||
simulation_timestamp=time.strftime("%Y-%m-%d %H:%M:%S"), |
||||
metrics=None |
||||
) |
||||
print(f"✗ 因子模拟异常: {expression}") |
||||
print(f" 耗时: {format_time(time_consuming)},异常: {str(e)}") |
||||
|
||||
return result |
||||
|
||||
"""打印成功因子的关键指标""" |
||||
def _print_success_metrics(self, metrics: Dict[str, Any]): |
||||
# 添加空值检查 |
||||
if not metrics: |
||||
print(" 无指标数据") |
||||
return |
||||
|
||||
print(" 关键指标 (训练集):") |
||||
# 从原始metrics数据中提取训练集指标 |
||||
train_data = metrics.get('train', {}) or {} |
||||
key_metrics = [ |
||||
('夏普比率', 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}") # 衡量风险调整后的收益 |
||||
# 年化收益率 |
||||
# 显示样本外测试的夏普比率(如果存在) # 最大亏损幅度 |
||||
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"因子列表: {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"本批总耗时: {format_time(batch_total_time)}") |
||||
print(f"{'=' * 60}") |
||||
|
||||
return batch_results |
||||
|
||||
"""运行批量模拟""" |
||||
def run_simulation(self, alpha_list: List[str], batch_size: int = 3) -> List[SimulationResult]: |
||||
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) |
||||
|
||||
# 保存结果到文件 |
||||
save_results_to_file(all_results) |
||||
|
||||
return all_results |
||||
|
||||
"""打印结果汇总""" |
||||
def print_summary(self, results: List[SimulationResult], total_time: float): |
||||
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"总耗时: {format_time(total_time)}") |
||||
print(f"{'=' * 60}") |
||||
|
||||
success_expression_list = [] |
||||
|
||||
for i, result in enumerate(results, 1): |
||||
status_icon = "✓" if result.status == 'success' else "✗" |
||||
|
||||
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': |
||||
line_parts.append(f"原因: {result.description}") |
||||
|
||||
print("\t".join(line_parts)) |
||||
|
||||
save_success_alpha(success_expression_list) |
||||
@ -0,0 +1,32 @@ |
||||
# -*- coding: utf-8 -*- |
||||
"""数据实体模型""" |
||||
|
||||
from dataclasses import dataclass |
||||
from datetime import datetime |
||||
from typing import Optional |
||||
|
||||
|
||||
@dataclass |
||||
class SimulationResult: |
||||
"""模拟结果实体""" |
||||
expression: str |
||||
time_consuming: float |
||||
status: str # 'ok' or 'err' |
||||
timestamp: str |
||||
alpha_id: Optional[str] = None |
||||
message: Optional[str] = None |
||||
|
||||
|
||||
@dataclass |
||||
class AlphaExpression: |
||||
"""Alpha表达式实体""" |
||||
expression: str |
||||
unused: bool = True |
||||
created_time: Optional[datetime] = None |
||||
|
||||
|
||||
@dataclass |
||||
class TokenInfo: |
||||
"""认证令牌信息""" |
||||
token: str |
||||
expiry: int |
||||
@ -1,168 +0,0 @@ |
||||
{ |
||||
"schema": { |
||||
"name": "yearly-stats", |
||||
"title": "Yearly Stats", |
||||
"properties": [ |
||||
{ |
||||
"name": "year", |
||||
"title": "Year", |
||||
"type": "year" |
||||
}, |
||||
{ |
||||
"name": "pnl", |
||||
"title": "PnL", |
||||
"type": "amount" |
||||
}, |
||||
{ |
||||
"name": "bookSize", |
||||
"title": "Book Size", |
||||
"type": "amount" |
||||
}, |
||||
{ |
||||
"name": "longCount", |
||||
"title": "Long Count", |
||||
"type": "integer" |
||||
}, |
||||
{ |
||||
"name": "shortCount", |
||||
"title": "Short Count", |
||||
"type": "integer" |
||||
}, |
||||
{ |
||||
"name": "turnover", |
||||
"title": "Turnover", |
||||
"type": "percent" |
||||
}, |
||||
{ |
||||
"name": "sharpe", |
||||
"title": "Sharpe", |
||||
"type": "decimal" |
||||
}, |
||||
{ |
||||
"name": "returns", |
||||
"title": "Returns", |
||||
"type": "percent" |
||||
}, |
||||
{ |
||||
"name": "drawdown", |
||||
"title": "Drawdown", |
||||
"type": "percent" |
||||
}, |
||||
{ |
||||
"name": "margin", |
||||
"title": "Margin", |
||||
"type": "permyriad" |
||||
}, |
||||
{ |
||||
"name": "fitness", |
||||
"title": "Fitness", |
||||
"type": "decimal" |
||||
}, |
||||
{ |
||||
"name": "stage", |
||||
"title": "Stage", |
||||
"type": "string" |
||||
} |
||||
] |
||||
}, |
||||
"records": [ |
||||
[ |
||||
"2018", |
||||
347052.0, |
||||
20000000, |
||||
1081, |
||||
1083, |
||||
0.3727, |
||||
1.54, |
||||
0.0365, |
||||
0.0156, |
||||
0.000196, |
||||
0.48, |
||||
"TRAIN" |
||||
], |
||||
[ |
||||
"2019", |
||||
190205.0, |
||||
20000000, |
||||
1364, |
||||
1359, |
||||
0.3659, |
||||
0.83, |
||||
0.0189, |
||||
0.0353, |
||||
0.000103, |
||||
0.19, |
||||
"TRAIN" |
||||
], |
||||
[ |
||||
"2020", |
||||
1554201.0, |
||||
20000000, |
||||
1348, |
||||
1340, |
||||
0.3639, |
||||
4.49, |
||||
0.1682, |
||||
0.0145, |
||||
0.000925, |
||||
3.05, |
||||
"TRAIN" |
||||
], |
||||
[ |
||||
"2021", |
||||
584087.0, |
||||
20000000, |
||||
1435, |
||||
1424, |
||||
0.3652, |
||||
1.41, |
||||
0.0579, |
||||
0.0253, |
||||
0.000317, |
||||
0.56, |
||||
"TRAIN" |
||||
], |
||||
[ |
||||
"2022", |
||||
31117.0, |
||||
20000000, |
||||
1441, |
||||
1434, |
||||
0.3446, |
||||
2.08, |
||||
0.0648, |
||||
0.004, |
||||
0.000376, |
||||
0.9, |
||||
"TRAIN" |
||||
], |
||||
[ |
||||
"2022", |
||||
443804.0, |
||||
20000000, |
||||
1415, |
||||
1417, |
||||
0.3623, |
||||
1.19, |
||||
0.0464, |
||||
0.0349, |
||||
0.000256, |
||||
0.43, |
||||
"TEST" |
||||
], |
||||
[ |
||||
"2023", |
||||
68779.0, |
||||
20000000, |
||||
1405, |
||||
1394, |
||||
0.3554, |
||||
6.22, |
||||
0.1323, |
||||
0.0019, |
||||
0.000744, |
||||
3.79, |
||||
"TEST" |
||||
] |
||||
] |
||||
} |
||||
@ -1,137 +0,0 @@ |
||||
{ |
||||
"id": "KP0WWZ6l", |
||||
"type": "REGULAR", |
||||
"author": "YC93384", |
||||
"settings": { |
||||
"instrumentType": "EQUITY", |
||||
"region": "USA", |
||||
"universe": "TOP3000", |
||||
"delay": 1, |
||||
"decay": 0, |
||||
"neutralization": "SUBINDUSTRY", |
||||
"truncation": 0.08, |
||||
"pasteurization": "ON", |
||||
"unitHandling": "VERIFY", |
||||
"nanHandling": "OFF", |
||||
"maxTrade": "OFF", |
||||
"language": "FASTEXPR", |
||||
"visualization": false, |
||||
"startDate": "2018-01-20", |
||||
"endDate": "2023-01-20", |
||||
"testPeriod": "P1Y" |
||||
}, |
||||
"regular": { |
||||
"code": "rank(ts_sum(vec_avg(nws12_afterhsz_sl), 60)) * 0.7 + rank(-ts_delta(close, 2)) * 0.3", |
||||
"description": null, |
||||
"operatorCount": 9 |
||||
}, |
||||
"dateCreated": "2025-11-13T09:22:47-05:00", |
||||
"dateSubmitted": null, |
||||
"dateModified": "2025-11-13T09:22:47-05:00", |
||||
"name": null, |
||||
"favorite": false, |
||||
"hidden": false, |
||||
"color": null, |
||||
"category": null, |
||||
"tags": [], |
||||
"classifications": [], |
||||
"grade": "INFERIOR", |
||||
"stage": "IS", |
||||
"status": "UNSUBMITTED", |
||||
"is": { |
||||
"pnl": 3219244, |
||||
"bookSize": 20000000, |
||||
"longCount": 1332, |
||||
"shortCount": 1328, |
||||
"turnover": 0.3657, |
||||
"returns": 0.0651, |
||||
"drawdown": 0.0353, |
||||
"margin": 0.000356, |
||||
"sharpe": 1.93, |
||||
"fitness": 0.81, |
||||
"startDate": "2018-01-20", |
||||
"checks": [ |
||||
{ |
||||
"name": "LOW_SHARPE", |
||||
"result": "PASS", |
||||
"limit": 1.25, |
||||
"value": 1.93 |
||||
}, |
||||
{ |
||||
"name": "LOW_FITNESS", |
||||
"result": "FAIL", |
||||
"limit": 1.0, |
||||
"value": 0.81 |
||||
}, |
||||
{ |
||||
"name": "LOW_TURNOVER", |
||||
"result": "PASS", |
||||
"limit": 0.01, |
||||
"value": 0.3657 |
||||
}, |
||||
{ |
||||
"name": "HIGH_TURNOVER", |
||||
"result": "PASS", |
||||
"limit": 0.7, |
||||
"value": 0.3657 |
||||
}, |
||||
{ |
||||
"name": "CONCENTRATED_WEIGHT", |
||||
"result": "PASS" |
||||
}, |
||||
{ |
||||
"name": "LOW_SUB_UNIVERSE_SHARPE", |
||||
"result": "PASS", |
||||
"limit": 0.84, |
||||
"value": 1.7 |
||||
}, |
||||
{ |
||||
"name": "SELF_CORRELATION", |
||||
"result": "PENDING" |
||||
}, |
||||
{ |
||||
"name": "MATCHES_COMPETITION", |
||||
"result": "PASS", |
||||
"competitions": [ |
||||
{ |
||||
"id": "challenge", |
||||
"name": "Challenge" |
||||
} |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
"os": null, |
||||
"train": { |
||||
"pnl": 2718449, |
||||
"bookSize": 20000000, |
||||
"longCount": 1311, |
||||
"shortCount": 1306, |
||||
"turnover": 0.3665, |
||||
"returns": 0.0689, |
||||
"drawdown": 0.0353, |
||||
"margin": 0.000376, |
||||
"fitness": 0.92, |
||||
"sharpe": 2.13, |
||||
"startDate": "2018-01-20" |
||||
}, |
||||
"test": { |
||||
"pnl": 512583, |
||||
"bookSize": 20000000, |
||||
"longCount": 1415, |
||||
"shortCount": 1416, |
||||
"turnover": 0.362, |
||||
"returns": 0.0509, |
||||
"drawdown": 0.0349, |
||||
"margin": 0.000281, |
||||
"fitness": 0.5, |
||||
"sharpe": 1.33, |
||||
"startDate": "2022-01-20" |
||||
}, |
||||
"prod": null, |
||||
"competitions": null, |
||||
"themes": null, |
||||
"pyramids": null, |
||||
"pyramidThemes": null, |
||||
"team": null |
||||
} |
||||
@ -1,22 +0,0 @@ |
||||
{ |
||||
"id": "3q4OCMgw4MFa8k16tdsYLml", |
||||
"type": "REGULAR", |
||||
"settings": { |
||||
"instrumentType": "EQUITY", |
||||
"region": "USA", |
||||
"universe": "TOP3000", |
||||
"delay": 1, |
||||
"decay": 0, |
||||
"neutralization": "SUBINDUSTRY", |
||||
"truncation": 0.08, |
||||
"pasteurization": "ON", |
||||
"unitHandling": "VERIFY", |
||||
"nanHandling": "OFF", |
||||
"maxTrade": "OFF", |
||||
"language": "FASTEXPR", |
||||
"visualization": false |
||||
}, |
||||
"regular": "rank(ts_sum(vec_avg(nws12_afterhsz_sl), 60)) * 0.7 + rank(-ts_delta(close, 2)) * 0.3", |
||||
"status": "COMPLETE", |
||||
"alpha": "KP0WWZ6l" |
||||
} |
||||
@ -0,0 +1,714 @@ |
||||
aiobotocore @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_b3e4znaej2/croot/aiobotocore_1680004294920/work |
||||
aiofiles==24.1.0 |
||||
aiohappyeyeballs==2.6.1 |
||||
aiohttp==3.11.14 |
||||
aioitertools @ file:///tmp/build/80754af9/aioitertools_1607109665762/work |
||||
aiosignal @ file:///tmp/build/80754af9/aiosignal_1637843061372/work |
||||
aiosqlite @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_13w97vul7u/croot/aiosqlite_1683773912122/work |
||||
alabaster @ file:///home/ktietz/src/ci/alabaster_1611921544520/work |
||||
altgraph==0.17.4 |
||||
anaconda-catalogs @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_737qok84ed/croot/anaconda-catalogs_1685727302903/work |
||||
anaconda-client==1.11.3 |
||||
anaconda-navigator==2.4.2 |
||||
anaconda-project @ file:///Users/ec2-user/ci_py311/anaconda-project_1678395481364/work |
||||
annotated-types==0.7.0 |
||||
anyio==3.7.1 |
||||
appdirs==1.4.4 |
||||
applaunchservices @ file:///Users/ec2-user/ci_py311/applaunchservices_1678390181983/work |
||||
appnope @ file:///Users/ec2-user/ci_py311/appnope_1678317440516/work |
||||
appscript @ file:///Users/ec2-user/ci_py311/appscript_1678390203562/work |
||||
argon2-cffi @ file:///opt/conda/conda-bld/argon2-cffi_1645000214183/work |
||||
argon2-cffi-bindings @ file:///Users/ec2-user/ci_py311/argon2-cffi-bindings_1678317076583/work |
||||
arrow @ file:///Users/ec2-user/ci_py311/arrow_1678325845580/work |
||||
art==6.4 |
||||
astroid @ file:///Users/ec2-user/ci_py311/astroid_1678323235198/work |
||||
astropy @ file:///Users/ec2-user/ci_py311_2/astropy_1679335070862/work |
||||
asttokens @ file:///opt/conda/conda-bld/asttokens_1646925590279/work |
||||
astunparse==1.6.3 |
||||
async-timeout @ file:///Users/ec2-user/ci_py311/async-timeout_1678320112070/work |
||||
atomicwrites==1.4.0 |
||||
attrs==25.3.0 |
||||
Automat @ file:///tmp/build/80754af9/automat_1600298431173/work |
||||
autopep8 @ file:///opt/conda/conda-bld/autopep8_1650463822033/work |
||||
Babel @ file:///Users/ec2-user/ci_py311/babel_1678318085010/work |
||||
backcall @ file:///home/ktietz/src/ci/backcall_1611930011877/work |
||||
backoff==2.2.1 |
||||
backports.functools-lru-cache @ file:///tmp/build/80754af9/backports.functools_lru_cache_1618170165463/work |
||||
backports.tempfile @ file:///home/linux1/recipes/ci/backports.tempfile_1610991236607/work |
||||
backports.weakref==1.0.post1 |
||||
base58==2.1.1 |
||||
bcrypt @ file:///Users/ec2-user/ci_py311/bcrypt_1678325873219/work |
||||
beautifulsoup4==4.14.0 |
||||
better-proxy==1.1.5 |
||||
betterproto2==0.5.1 |
||||
bidict==0.23.1 |
||||
binaryornot @ file:///tmp/build/80754af9/binaryornot_1617751525010/work |
||||
bip39==0.0.2 |
||||
bitarray==2.9.2 |
||||
black @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_1f1pcodmuo/croot/black_1680737253550/work |
||||
bleach @ file:///opt/conda/conda-bld/bleach_1641577558959/work |
||||
blinker==1.7.0 |
||||
bokeh @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_f0dguf6k4i/croot/bokeh_1684534020835/work |
||||
boltons @ file:///Users/ec2-user/ci_py311/boltons_1678396074811/work |
||||
boto3 @ file:///Users/ec2-user/ci_py311_2/boto3_1679335351182/work |
||||
botocore @ file:///Users/ec2-user/ci_py311/botocore_1678320133200/work |
||||
Bottleneck @ file:///Users/ec2-user/ci_py311/bottleneck_1678322312632/work |
||||
Brotli==1.1.0 |
||||
brotlipy==0.7.0 |
||||
bs4==0.0.2 |
||||
build==1.2.2.post1 |
||||
buildozer==1.5.0 |
||||
cairocffi==1.6.1 |
||||
CairoSVG==2.7.1 |
||||
candlelite==1.0.17 |
||||
canoser==0.8.2 |
||||
captchatools==1.5.0 |
||||
certifi==2025.8.3 |
||||
cffi @ file:///Users/ec2-user/ci_py311/cffi_1678315312775/work |
||||
chardet @ file:///Users/ec2-user/ci_py311/chardet_1678326102860/work |
||||
charset-normalizer @ file:///tmp/build/80754af9/charset-normalizer_1630003229654/work |
||||
ci-info==0.3.0 |
||||
ckzg==1.0.1 |
||||
click @ file:///Users/ec2-user/ci_py311/click_1678318124837/work |
||||
cloudpickle @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_c57ujq_pgm/croot/cloudpickle_1683040025620/work |
||||
clyent==1.2.2 |
||||
colorama @ file:///Users/ec2-user/ci_py311/colorama_1678320227414/work |
||||
colorcet @ file:///Users/ec2-user/ci_py311/colorcet_1678380145131/work |
||||
comm @ file:///Users/ec2-user/ci_py311/comm_1678317779525/work |
||||
conda @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_a9qfrev42r/croot/conda_1685025193092/work |
||||
conda-build @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_e5ocr04fqn/croot/conda-build_1685026138121/work |
||||
conda-content-trust @ file:///Users/ec2-user/ci_py311/conda-content-trust_1678409283937/work |
||||
conda-libmamba-solver @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_b7jucd8kvj/croot/conda-libmamba-solver_1685032330942/work/src |
||||
conda-pack @ file:///tmp/build/80754af9/conda-pack_1611163042455/work |
||||
conda-package-handling @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_f61sssj1s3/croot/conda-package-handling_1685024797154/work |
||||
conda-repo-cli==1.0.41 |
||||
conda-token @ file:///Users/paulyim/miniconda3/envs/c3i/conda-bld/conda-token_1662660369760/work |
||||
conda-verify==3.4.2 |
||||
conda_index @ file:///Users/ec2-user/ci_py311/conda-index_1678409305677/work |
||||
conda_package_streaming @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_78ue32m8ay/croot/conda-package-streaming_1685019689310/work |
||||
configobj==5.0.8 |
||||
configparser==6.0.0 |
||||
constantly==15.1.0 |
||||
contourpy @ file:///Users/ec2-user/ci_py311/contourpy_1678322361099/work |
||||
cookiecutter @ file:///opt/conda/conda-bld/cookiecutter_1649151442564/work |
||||
cryptography @ file:///Users/ec2-user/ci_py311_2/cryptography_1679335457662/work |
||||
cssselect==1.1.0 |
||||
cssselect2==0.7.0 |
||||
cycler @ file:///tmp/build/80754af9/cycler_1637851556182/work |
||||
Cython==3.0.11 |
||||
cytoolz @ file:///Users/ec2-user/ci_py311/cytoolz_1678326214370/work |
||||
dask @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_ccdxmmxbox/croot/dask-core_1686782920612/work |
||||
dataclasses-json==0.6.7 |
||||
DataRecorder==3.6.2 |
||||
datashader @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_93l60mzvvb/croot/datashader_1685542975569/work |
||||
datashape==0.5.4 |
||||
debugpy @ file:///Users/ec2-user/ci_py311/debugpy_1678317801115/work |
||||
decorator @ file:///opt/conda/conda-bld/decorator_1643638310831/work |
||||
defusedxml @ file:///tmp/build/80754af9/defusedxml_1615228127516/work |
||||
Deprecated==1.2.18 |
||||
diff-match-patch @ file:///Users/ktietz/demo/mc3/conda-bld/diff-match-patch_1630511840874/work |
||||
dill @ file:///Users/ec2-user/ci_py311/dill_1678323290904/work |
||||
distlib==0.3.9 |
||||
distributed @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_95i88jlqtp/croot/distributed_1686866052419/work |
||||
distro==1.9.0 |
||||
dnspython==2.4.1 |
||||
docstring-to-markdown @ file:///Users/ec2-user/ci_py311/docstring-to-markdown_1678326320721/work |
||||
docutils==0.22.1 |
||||
docx==0.2.4 |
||||
DownloadKit==2.0.7 |
||||
DrissionPage==4.1.0.17 |
||||
dukpy==0.4.0 |
||||
easygui==0.98.3 |
||||
email-validator==2.0.0.post2 |
||||
entrypoints @ file:///Users/ec2-user/ci_py311/entrypoints_1678316169365/work |
||||
epcpy==0.1.7 |
||||
et-xmlfile==1.1.0 |
||||
etelemetry==0.3.1 |
||||
eth-account==0.11.2 |
||||
eth-hash==0.7.0 |
||||
eth-keyfile==0.8.1 |
||||
eth-keys==0.5.1 |
||||
eth-rlp==1.0.1 |
||||
eth-typing==4.2.1 |
||||
eth-utils==4.1.0 |
||||
eth_abi==5.1.0 |
||||
executing @ file:///opt/conda/conda-bld/executing_1646925071911/work |
||||
fake-useragent==1.5.1 |
||||
fastapi==0.104.1 |
||||
fastjsonschema @ file:///Users/ec2-user/ci_py311_2/python-fastjsonschema_1679338737111/work |
||||
filelock==3.16.1 |
||||
filetype==1.2.0 |
||||
fitz==0.0.1.dev2 |
||||
flake8 @ file:///Users/ec2-user/ci_py311/flake8_1678326404511/work |
||||
Flask @ file:///Users/ec2-user/ci_py311/flask_1678380788105/work |
||||
fonttools==4.25.0 |
||||
fqdn==1.5.1 |
||||
frozenlist @ file:///Users/ec2-user/ci_py311/frozenlist_1678318685088/work |
||||
fsspec @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_d9zxascxg8/croot/fsspec_1679418997424/work |
||||
future @ file:///Users/ec2-user/ci_py311_2/future_1679335881731/work |
||||
genshinhelper==2.1.3 |
||||
gensim @ file:///Users/ec2-user/ci_py311/gensim_1678412014794/work |
||||
glob2 @ file:///home/linux1/recipes/ci/glob2_1610991677669/work |
||||
gmpy2 @ file:///Users/ec2-user/ci_py311/gmpy2_1678380831980/work |
||||
gql==3.5.3 |
||||
graphql-core==3.2.6 |
||||
greenlet==3.1.1 |
||||
grpclib==0.4.8 |
||||
h11==0.16.0 |
||||
h2==4.1.0 |
||||
h5py @ file:///Users/ec2-user/ci_py311/h5py_1678381005308/work |
||||
HeapDict @ file:///Users/ktietz/demo/mc3/conda-bld/heapdict_1630598515714/work |
||||
hexbytes==0.3.1 |
||||
holoviews @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_7a7dicrx1g/croot/holoviews_1686339350598/work |
||||
hpack==4.0.0 |
||||
httpcore==1.0.9 |
||||
httplib2==0.22.0 |
||||
httptools==0.6.0 |
||||
httpx==0.25.2 |
||||
httpx-sse==0.4.0 |
||||
hvplot @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_4dben4g_th/croot/hvplot_1685998195310/work |
||||
hyperframe==6.0.1 |
||||
hyperlink @ file:///tmp/build/80754af9/hyperlink_1610130746837/work |
||||
idna @ file:///Users/ec2-user/ci_py311/idna_1678315819133/work |
||||
ifaddr==0.2.0 |
||||
imagecodecs @ file:///Users/ec2-user/ci_py311_2/imagecodecs_1679336141260/work |
||||
imageio @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_47v6nbs3l9/croot/imageio_1687264946242/work |
||||
imagesize @ file:///Users/ec2-user/ci_py311/imagesize_1678377399148/work |
||||
imap-tools==1.10.0 |
||||
imbalanced-learn @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_a1ju_tsc7c/croot/imbalanced-learn_1685020900729/work |
||||
importlib-metadata @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_81_20mq0d8/croot/importlib-metadata_1678997090664/work |
||||
incremental @ file:///tmp/build/80754af9/incremental_1636629750599/work |
||||
inflection==0.5.1 |
||||
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work |
||||
intake @ file:///Users/ec2-user/ci_py311_2/intake_1679336302724/work |
||||
intervaltree @ file:///Users/ktietz/demo/mc3/conda-bld/intervaltree_1630511889664/work |
||||
ipykernel @ file:///Users/ec2-user/ci_py311/ipykernel_1678318220696/work |
||||
ipython @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_cd4ia5pr17/croot/ipython_1680701875298/work |
||||
ipython-genutils @ file:///tmp/build/80754af9/ipython_genutils_1606773439826/work |
||||
ipywidgets @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_f5atknkudc/croot/ipywidgets_1679394812720/work |
||||
isodate==0.6.1 |
||||
isoduration==20.11.0 |
||||
isort @ file:///tmp/build/80754af9/isort_1628603791788/work |
||||
itemadapter @ file:///tmp/build/80754af9/itemadapter_1626442940632/work |
||||
itemloaders @ file:///opt/conda/conda-bld/itemloaders_1646805235997/work |
||||
itsdangerous==2.2.0 |
||||
jaraco.classes @ file:///tmp/build/80754af9/jaraco.classes_1620983179379/work |
||||
jedi @ file:///Users/ec2-user/ci_py311_2/jedi_1679336327335/work |
||||
jellyfish @ file:///Users/ec2-user/ci_py311/jellyfish_1678392216202/work |
||||
Jinja2==3.1.6 |
||||
jinja2-time @ file:///opt/conda/conda-bld/jinja2-time_1649251842261/work |
||||
jiter==0.8.2 |
||||
jittor==1.3.8.5 |
||||
jmespath @ file:///Users/ktietz/demo/mc3/conda-bld/jmespath_1630583964805/work |
||||
joblib @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_dfriz0qjwt/croot/joblib_1685113297703/work |
||||
Js2Py_3.13==0.74.1 |
||||
json5 @ file:///tmp/build/80754af9/json5_1624432770122/work |
||||
jsonalias==0.1.1 |
||||
jsonpatch==1.33 |
||||
jsonpointer==2.1 |
||||
jsonschema==4.23.0 |
||||
jsonschema-specifications==2025.4.1 |
||||
jtorch==0.1.7 |
||||
jupyter @ file:///Users/ec2-user/ci_py311/jupyter_1678377791770/work |
||||
jupyter-console @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_e8qcp1kdie/croot/jupyter_console_1679999714867/work |
||||
jupyter-events @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_f0yqwpn5u1/croot/jupyter_events_1684268046871/work |
||||
jupyter-ydoc @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_79b9hk1z3q/croot/jupyter_ydoc_1683747244664/work |
||||
jupyter_client @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_5e4bbpqn9e/croot/jupyter_client_1680171866753/work |
||||
jupyter_core @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_b82fz_h369/croot/jupyter_core_1679906581737/work |
||||
jupyter_server @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_b7pddqvxoj/croot/jupyter_server_1686059483368/work |
||||
jupyter_server_fileid @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_b0lffopjbp/croot/jupyter_server_fileid_1684273621123/work |
||||
jupyter_server_terminals @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_257krljdmq/croot/jupyter_server_terminals_1686870730796/work |
||||
jupyter_server_ydoc @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_6848h2a_93/croot/jupyter_server_ydoc_1686768718335/work |
||||
jupyterlab @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_502x016ek3/croot/jupyterlab_1686179671461/work |
||||
jupyterlab-pygments @ file:///tmp/build/80754af9/jupyterlab_pygments_1601490720602/work |
||||
jupyterlab-widgets @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_9btffb27id/croot/jupyterlab_widgets_1679055288818/work |
||||
jupyterlab_server @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_9039tf6tpv/croot/jupyterlab_server_1680792539169/work |
||||
kaitaistruct==0.10 |
||||
keyring @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_2ds0bchnl2/croot/keyring_1678999223818/work |
||||
Kivy==2.3.0 |
||||
Kivy-Garden==0.1.5 |
||||
kiwisolver @ file:///Users/ec2-user/ci_py311/kiwisolver_1678322457192/work |
||||
langchain==0.3.14 |
||||
langchain-community==0.3.14 |
||||
langchain-core==0.3.29 |
||||
langchain-text-splitters==0.3.4 |
||||
langsmith==0.2.10 |
||||
lazy-object-proxy @ file:///Users/ec2-user/ci_py311/lazy-object-proxy_1678322504286/work |
||||
lazy_loader @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_02apt1h75k/croot/lazy_loader_1687264081288/work |
||||
libarchive-c @ file:///tmp/build/80754af9/python-libarchive-c_1617780486945/work |
||||
libmambapy @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_65seb320zf/croot/mamba-split_1680093070986/work/libmambapy |
||||
linkify-it-py @ file:///Users/ec2-user/ci_py311/linkify-it-py_1678413480728/work |
||||
llvmlite @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_39tj5og13d/croot/llvmlite_1683555130919/work |
||||
lmdb @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_88zbo0vn66/croot/python-lmdb_1682522360781/work |
||||
locket @ file:///Users/ec2-user/ci_py311/locket_1678322541585/work |
||||
loguru==0.7.2 |
||||
looseversion==1.3.0 |
||||
lru-dict==1.2.0 |
||||
lxml==6.0.2 |
||||
lz4 @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_7fl2lzb5wh/croot/lz4_1686057901919/work |
||||
m3u8==6.0.0 |
||||
macholib==1.16.3 |
||||
Markdown @ file:///Users/ec2-user/ci_py311/markdown_1678377870854/work |
||||
markdown-it-py @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_43xjt6hz0x/croot/markdown-it-py_1684279911135/work |
||||
markdown2==2.5.4 |
||||
MarkupSafe==3.0.3 |
||||
marshmallow==3.24.1 |
||||
matplotlib @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_41fhwn4tj9/croot/matplotlib-suite_1679593479845/work |
||||
matplotlib-inline @ file:///Users/ec2-user/ci_py311/matplotlib-inline_1678317544666/work |
||||
mccabe @ file:///opt/conda/conda-bld/mccabe_1644221741721/work |
||||
mdit-py-plugins @ file:///Users/ec2-user/ci_py311/mdit-py-plugins_1678417716573/work |
||||
mdurl @ file:///Users/ec2-user/ci_py311/mdurl_1678381820326/work |
||||
mistune @ file:///Users/ec2-user/ci_py311/mistune_1678317272228/work |
||||
mmh3==4.1.0 |
||||
mnemonic==0.21 |
||||
modulegraph==0.19.6 |
||||
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work |
||||
mpmath==1.2.1 |
||||
msgpack @ file:///Users/ec2-user/ci_py311/msgpack-python_1678318264150/work |
||||
multidict @ file:///Users/ec2-user/ci_py311/multidict_1678318765630/work |
||||
multipledispatch @ file:///Users/ec2-user/ci_py311/multipledispatch_1678392901644/work |
||||
munkres==1.1.4 |
||||
mutf8==1.0.6 |
||||
mypy==1.18.2 |
||||
mypy_extensions==1.1.0 |
||||
names==0.3.0 |
||||
navigator-updater==0.4.0 |
||||
nbclassic @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_e9be4uk5qu/croot/nbclassic_1681756175065/work |
||||
nbclient @ file:///Users/ec2-user/ci_py311/nbclient_1678317300721/work |
||||
nbconvert @ file:///Users/ec2-user/ci_py311/nbconvert_1678317567483/work |
||||
nbformat @ file:///Users/ec2-user/ci_py311/nbformat_1678317010390/work |
||||
nest-asyncio @ file:///Users/ec2-user/ci_py311/nest-asyncio_1678316288195/work |
||||
networkx @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_1a72gktq2s/croot/networkx_1678964337061/work |
||||
nibabel==5.1.0 |
||||
nicegui==2.24.1 |
||||
nipype==1.8.6 |
||||
nltk @ file:///opt/conda/conda-bld/nltk_1645628263994/work |
||||
nodeenv==1.9.1 |
||||
notebook @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_be_2kh1kd4/croot/notebook_1681756176866/work |
||||
notebook_shim @ file:///Users/ec2-user/ci_py311/notebook-shim_1678318293647/work |
||||
numba @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_93pzbiav_e/croot/numba_1684245526578/work |
||||
numexpr @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_1b50c1js9s/croot/numexpr_1683227065029/work |
||||
numpy==1.26.3 |
||||
numpydoc @ file:///Users/ec2-user/ci_py311/numpydoc_1678393034712/work |
||||
OdooRPC==0.10.1 |
||||
okx==2.1.1 |
||||
okx-api==1.0.5 |
||||
ollama==0.4.5 |
||||
openai==1.59.6 |
||||
opencv-python==4.8.1.78 |
||||
openpyxl==3.0.10 |
||||
orjson==3.10.13 |
||||
outcome==1.3.0.post0 |
||||
packaging==24.2 |
||||
pandas==1.5.3 |
||||
pandocfilters @ file:///opt/conda/conda-bld/pandocfilters_1643405455980/work |
||||
panel @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_dfq8ysliwf/croot/panel_1686058338704/work |
||||
param @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_eb_xu6rgzh/croot/param_1684915322419/work |
||||
parsel @ file:///Users/ec2-user/ci_py311/parsel_1678382184303/work |
||||
parsimonious==0.10.0 |
||||
parso @ file:///opt/conda/conda-bld/parso_1641458642106/work |
||||
partd @ file:///opt/conda/conda-bld/partd_1647245470509/work |
||||
pathlib @ file:///Users/ktietz/demo/mc3/conda-bld/pathlib_1629713961906/work |
||||
pathspec @ file:///Users/ec2-user/ci_py311_2/pathspec_1679337122817/work |
||||
patsy==0.5.3 |
||||
paux==1.0.14 |
||||
pdfminer==20191125 |
||||
pdfminer3k==1.3.4 |
||||
pdfparanoia==0.0.17 |
||||
pendulum==3.0.0 |
||||
pep8==1.7.1 |
||||
pexpect @ file:///tmp/build/80754af9/pexpect_1605563209008/work |
||||
pickleshare @ file:///tmp/build/80754af9/pickleshare_1606932040724/work |
||||
pika==1.3.2 |
||||
Pillow==9.4.0 |
||||
pkginfo @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_d976p03z5u/croot/pkginfo_1679431175529/work |
||||
platformdirs==4.3.6 |
||||
playwright==1.50.0 |
||||
plotly @ file:///Users/ec2-user/ci_py311/plotly_1678382250051/work |
||||
pluggy @ file:///Users/ec2-user/ci_py311/pluggy_1678315400971/work |
||||
ply==3.11 |
||||
pooch @ file:///tmp/build/80754af9/pooch_1623324770023/work |
||||
potracer==0.0.4 |
||||
poyo @ file:///tmp/build/80754af9/poyo_1617751526755/work |
||||
prometheus-client @ file:///Users/ec2-user/ci_py311_2/prometheus_client_1679340232148/work |
||||
prompt-toolkit @ file:///Users/ec2-user/ci_py311/prompt-toolkit_1678317707969/work |
||||
propcache==0.3.0 |
||||
Protego @ file:///tmp/build/80754af9/protego_1598657180827/work |
||||
protobuf==5.26.1 |
||||
prov==2.0.0 |
||||
pscript==0.7.7 |
||||
psutil @ file:///Users/ec2-user/ci_py311_2/psutil_1679337242143/work |
||||
psycopg2==2.9.9 |
||||
ptyprocess @ file:///tmp/build/80754af9/ptyprocess_1609355006118/work/dist/ptyprocess-0.7.0-py2.py3-none-any.whl |
||||
pure-eval @ file:///opt/conda/conda-bld/pure_eval_1646925070566/work |
||||
py-cpuinfo @ file:///Users/ktietz/demo/mc3/conda-bld/py-cpuinfo_1629480366017/work |
||||
py2app==0.28.6 |
||||
pyarrow==11.0.0 |
||||
pyasn1 @ file:///Users/ktietz/demo/mc3/conda-bld/pyasn1_1629708007385/work |
||||
pyasn1-modules==0.2.8 |
||||
pycodestyle @ file:///Users/ec2-user/ci_py311/pycodestyle_1678324331308/work |
||||
pycosat @ file:///Users/ec2-user/ci_py311/pycosat_1678378899646/work |
||||
pycparser @ file:///tmp/build/80754af9/pycparser_1636541352034/work |
||||
pycryptodome==3.19.0 |
||||
pyct @ file:///Users/ec2-user/ci_py311/pyct_1678378955854/work |
||||
pycurl==7.45.2 |
||||
pydantic==2.11.9 |
||||
pydantic-extra-types==2.0.0 |
||||
pydantic-settings==2.7.1 |
||||
pydantic_core==2.33.2 |
||||
PyDispatcher==2.0.5 |
||||
pydocstyle @ file:///Users/ec2-user/ci_py311/pydocstyle_1678378981125/work |
||||
pydoll-python==1.3.3 |
||||
pydot==1.4.2 |
||||
pyee==12.0.0 |
||||
pyerfa @ file:///Users/ec2-user/ci_py311/pyerfa_1678379006730/work |
||||
pyflakes @ file:///Users/ec2-user/ci_py311/pyflakes_1678324357242/work |
||||
Pygments @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_cflayrfqsi/croot/pygments_1684279981084/work |
||||
PyICU==2.12 |
||||
pyinstaller==6.2.0 |
||||
pyinstaller-hooks-contrib==2023.10 |
||||
pyjsparser==2.7.1 |
||||
PyJWT @ file:///Users/ec2-user/ci_py311/pyjwt_1678379090382/work |
||||
pylint @ file:///Users/ec2-user/ci_py311/pylint_1678379112162/work |
||||
pylint-venv @ file:///Users/ec2-user/ci_py311/pylint-venv_1678393629931/work |
||||
pyls-spyder==0.4.0 |
||||
PyMuPDF==1.23.6 |
||||
PyMuPDFb==1.23.6 |
||||
pynanosvg==0.3.1 |
||||
pyobjc==10.3.1 |
||||
pyobjc-core==10.3.1 |
||||
pyobjc-framework-Accessibility==10.3.1 |
||||
pyobjc-framework-Accounts==10.3.1 |
||||
pyobjc-framework-AddressBook==10.3.1 |
||||
pyobjc-framework-AdServices==10.3.1 |
||||
pyobjc-framework-AdSupport==10.3.1 |
||||
pyobjc-framework-AppleScriptKit==10.3.1 |
||||
pyobjc-framework-AppleScriptObjC==10.3.1 |
||||
pyobjc-framework-ApplicationServices==10.3.1 |
||||
pyobjc-framework-AppTrackingTransparency==10.3.1 |
||||
pyobjc-framework-AudioVideoBridging==10.3.1 |
||||
pyobjc-framework-AuthenticationServices==10.3.1 |
||||
pyobjc-framework-AutomaticAssessmentConfiguration==10.3.1 |
||||
pyobjc-framework-Automator==10.3.1 |
||||
pyobjc-framework-AVFoundation==10.3.1 |
||||
pyobjc-framework-AVKit==10.3.1 |
||||
pyobjc-framework-AVRouting==10.3.1 |
||||
pyobjc-framework-BackgroundAssets==10.3.1 |
||||
pyobjc-framework-BusinessChat==10.3.1 |
||||
pyobjc-framework-CalendarStore==10.3.1 |
||||
pyobjc-framework-CallKit==10.3.1 |
||||
pyobjc-framework-CFNetwork==10.3.1 |
||||
pyobjc-framework-ClassKit==10.3.1 |
||||
pyobjc-framework-CloudKit==10.3.1 |
||||
pyobjc-framework-Cocoa==10.3.1 |
||||
pyobjc-framework-Collaboration==10.3.1 |
||||
pyobjc-framework-ColorSync==10.3.1 |
||||
pyobjc-framework-Contacts==10.3.1 |
||||
pyobjc-framework-ContactsUI==10.3.1 |
||||
pyobjc-framework-CoreAudio==10.3.1 |
||||
pyobjc-framework-CoreAudioKit==10.3.1 |
||||
pyobjc-framework-CoreBluetooth==10.3.1 |
||||
pyobjc-framework-CoreData==10.3.1 |
||||
pyobjc-framework-CoreHaptics==10.3.1 |
||||
pyobjc-framework-CoreLocation==10.3.1 |
||||
pyobjc-framework-CoreMedia==10.3.1 |
||||
pyobjc-framework-CoreMediaIO==10.3.1 |
||||
pyobjc-framework-CoreMIDI==10.3.1 |
||||
pyobjc-framework-CoreML==10.3.1 |
||||
pyobjc-framework-CoreMotion==10.3.1 |
||||
pyobjc-framework-CoreServices==10.3.1 |
||||
pyobjc-framework-CoreSpotlight==10.3.1 |
||||
pyobjc-framework-CoreText==10.3.1 |
||||
pyobjc-framework-CoreWLAN==10.3.1 |
||||
pyobjc-framework-CryptoTokenKit==10.3.1 |
||||
pyobjc-framework-DataDetection==10.3.1 |
||||
pyobjc-framework-DeviceCheck==10.3.1 |
||||
pyobjc-framework-DictionaryServices==10.3.1 |
||||
pyobjc-framework-DiscRecording==10.3.1 |
||||
pyobjc-framework-DiscRecordingUI==10.3.1 |
||||
pyobjc-framework-DiskArbitration==10.3.1 |
||||
pyobjc-framework-DVDPlayback==10.3.1 |
||||
pyobjc-framework-EventKit==10.3.1 |
||||
pyobjc-framework-ExceptionHandling==10.3.1 |
||||
pyobjc-framework-ExecutionPolicy==10.3.1 |
||||
pyobjc-framework-ExtensionKit==10.3.1 |
||||
pyobjc-framework-ExternalAccessory==10.3.1 |
||||
pyobjc-framework-FileProvider==10.3.1 |
||||
pyobjc-framework-FileProviderUI==10.3.1 |
||||
pyobjc-framework-FinderSync==10.3.1 |
||||
pyobjc-framework-FSEvents==10.3.1 |
||||
pyobjc-framework-GameCenter==10.3.1 |
||||
pyobjc-framework-GameController==10.3.1 |
||||
pyobjc-framework-GameKit==10.3.1 |
||||
pyobjc-framework-GameplayKit==10.3.1 |
||||
pyobjc-framework-HealthKit==10.3.1 |
||||
pyobjc-framework-ImageCaptureCore==10.3.1 |
||||
pyobjc-framework-InputMethodKit==10.3.1 |
||||
pyobjc-framework-InstallerPlugins==10.3.1 |
||||
pyobjc-framework-InstantMessage==10.3.1 |
||||
pyobjc-framework-Intents==10.3.1 |
||||
pyobjc-framework-IntentsUI==10.3.1 |
||||
pyobjc-framework-IOBluetooth==10.3.1 |
||||
pyobjc-framework-IOBluetoothUI==10.3.1 |
||||
pyobjc-framework-IOSurface==10.3.1 |
||||
pyobjc-framework-iTunesLibrary==10.3.1 |
||||
pyobjc-framework-KernelManagement==10.3.1 |
||||
pyobjc-framework-LatentSemanticMapping==10.3.1 |
||||
pyobjc-framework-LaunchServices==10.3.1 |
||||
pyobjc-framework-libdispatch==10.3.1 |
||||
pyobjc-framework-libxpc==10.3.1 |
||||
pyobjc-framework-LinkPresentation==10.3.1 |
||||
pyobjc-framework-LocalAuthentication==10.3.1 |
||||
pyobjc-framework-LocalAuthenticationEmbeddedUI==10.3.1 |
||||
pyobjc-framework-MailKit==10.3.1 |
||||
pyobjc-framework-MapKit==10.3.1 |
||||
pyobjc-framework-MediaAccessibility==10.3.1 |
||||
pyobjc-framework-MediaLibrary==10.3.1 |
||||
pyobjc-framework-MediaPlayer==10.3.1 |
||||
pyobjc-framework-MediaToolbox==10.3.1 |
||||
pyobjc-framework-Metal==10.3.1 |
||||
pyobjc-framework-MetalFX==10.3.1 |
||||
pyobjc-framework-MetalKit==10.3.1 |
||||
pyobjc-framework-MetalPerformanceShaders==10.3.1 |
||||
pyobjc-framework-MetalPerformanceShadersGraph==10.3.1 |
||||
pyobjc-framework-MetricKit==10.3.1 |
||||
pyobjc-framework-MLCompute==10.3.1 |
||||
pyobjc-framework-ModelIO==10.3.1 |
||||
pyobjc-framework-MultipeerConnectivity==10.3.1 |
||||
pyobjc-framework-NaturalLanguage==10.3.1 |
||||
pyobjc-framework-NetFS==10.3.1 |
||||
pyobjc-framework-Network==10.3.1 |
||||
pyobjc-framework-NetworkExtension==10.3.1 |
||||
pyobjc-framework-NotificationCenter==10.3.1 |
||||
pyobjc-framework-OpenDirectory==10.3.1 |
||||
pyobjc-framework-OSAKit==10.3.1 |
||||
pyobjc-framework-OSLog==10.3.1 |
||||
pyobjc-framework-PassKit==10.3.1 |
||||
pyobjc-framework-PencilKit==10.3.1 |
||||
pyobjc-framework-PHASE==10.3.1 |
||||
pyobjc-framework-Photos==10.3.1 |
||||
pyobjc-framework-PhotosUI==10.3.1 |
||||
pyobjc-framework-PreferencePanes==10.3.1 |
||||
pyobjc-framework-PushKit==10.3.1 |
||||
pyobjc-framework-Quartz==10.3.1 |
||||
pyobjc-framework-QuickLookThumbnailing==10.3.1 |
||||
pyobjc-framework-ReplayKit==10.3.1 |
||||
pyobjc-framework-SafariServices==10.3.1 |
||||
pyobjc-framework-SafetyKit==10.3.1 |
||||
pyobjc-framework-SceneKit==10.3.1 |
||||
pyobjc-framework-ScreenCaptureKit==10.3.1 |
||||
pyobjc-framework-ScreenSaver==10.3.1 |
||||
pyobjc-framework-ScreenTime==10.3.1 |
||||
pyobjc-framework-ScriptingBridge==10.3.1 |
||||
pyobjc-framework-SearchKit==10.3.1 |
||||
pyobjc-framework-Security==10.3.1 |
||||
pyobjc-framework-SecurityFoundation==10.3.1 |
||||
pyobjc-framework-SecurityInterface==10.3.1 |
||||
pyobjc-framework-ServiceManagement==10.3.1 |
||||
pyobjc-framework-SharedWithYou==10.3.1 |
||||
pyobjc-framework-SharedWithYouCore==10.3.1 |
||||
pyobjc-framework-ShazamKit==10.3.1 |
||||
pyobjc-framework-Social==10.3.1 |
||||
pyobjc-framework-SoundAnalysis==10.3.1 |
||||
pyobjc-framework-Speech==10.3.1 |
||||
pyobjc-framework-SpriteKit==10.3.1 |
||||
pyobjc-framework-StoreKit==10.3.1 |
||||
pyobjc-framework-SyncServices==10.3.1 |
||||
pyobjc-framework-SystemConfiguration==10.3.1 |
||||
pyobjc-framework-SystemExtensions==10.3.1 |
||||
pyobjc-framework-ThreadNetwork==10.3.1 |
||||
pyobjc-framework-UniformTypeIdentifiers==10.3.1 |
||||
pyobjc-framework-UserNotifications==10.3.1 |
||||
pyobjc-framework-UserNotificationsUI==10.3.1 |
||||
pyobjc-framework-VideoSubscriberAccount==10.3.1 |
||||
pyobjc-framework-VideoToolbox==10.3.1 |
||||
pyobjc-framework-Virtualization==10.3.1 |
||||
pyobjc-framework-Vision==10.3.1 |
||||
pyobjc-framework-WebKit==10.3.1 |
||||
pyodbc @ file:///Users/ec2-user/ci_py311/pyodbc_1678420730897/work |
||||
pyOpenSSL @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_19gfn1ib_u/croot/pyopenssl_1678965300171/work |
||||
pyotp==2.9.0 |
||||
pyparsing @ file:///Users/ec2-user/ci_py311/pyparsing_1678322828710/work |
||||
PyPDF2==1.26.0 |
||||
PyPDF4==1.27.0 |
||||
pyproject_hooks==1.2.0 |
||||
PyQt5-sip==12.11.0 |
||||
PyQt6==6.4.2 |
||||
pyqt6-plugins==6.4.2.2.3 |
||||
PyQt6-Qt6==6.4.3 |
||||
PyQt6-sip==13.6.0 |
||||
pyqt6-tools==6.4.2.3.3 |
||||
PyQt6-WebEngine==6.6.0 |
||||
PyQt6-WebEngine-Qt6==6.6.0 |
||||
pyright==1.1.405 |
||||
pyrsistent @ file:///Users/ec2-user/ci_py311/pyrsistent_1678316053523/work |
||||
PySocks @ file:///Users/ec2-user/ci_py311/pysocks_1678315868424/work |
||||
pysui==0.85.0 |
||||
pysui-fastcrypto==0.7.0 |
||||
pytest @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_bcnsxh_kaf/croot/pytest_1684171610545/work |
||||
python-barcode==0.15.1 |
||||
python-dateutil @ file:///tmp/build/80754af9/python-dateutil_1626374649649/work |
||||
python-dotenv==1.0.0 |
||||
python-engineio==4.12.2 |
||||
python-json-logger @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_49p5x2bjzn/croot/python-json-logger_1683823814668/work |
||||
python-lsp-black @ file:///Users/ec2-user/ci_py311/python-lsp-black_1678393907972/work |
||||
python-lsp-jsonrpc==1.0.0 |
||||
python-lsp-server @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_1fkjjx0yhx/croot/python-lsp-server_1681930400163/work |
||||
python-multipart==0.0.6 |
||||
python-slugify @ file:///tmp/build/80754af9/python-slugify_1620405669636/work |
||||
python-snappy @ file:///Users/ec2-user/ci_py311/python-snappy_1678388765172/work |
||||
python-socketio==5.13.0 |
||||
python-socks==2.7.1 |
||||
pytoolconfig @ file:///Users/ec2-user/ci_py311/pytoolconfig_1678324412360/work |
||||
pytz @ file:///Users/ec2-user/ci_py311/pytz_1678318034461/work |
||||
pyunormalize==15.1.0 |
||||
pyviz-comms @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_13yvjs0iia/croot/pyviz_comms_1685030724461/work |
||||
PyWavelets @ file:///Users/ec2-user/ci_py311/pywavelets_1678379192795/work |
||||
pyxnat==1.6 |
||||
PyYAML==6.0.2 |
||||
pyzmq @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_e6wiufh44w/croot/pyzmq_1686601381524/work |
||||
QDarkStyle @ file:///tmp/build/80754af9/qdarkstyle_1617386714626/work |
||||
qstylizer @ file:///Users/ec2-user/ci_py311/qstylizer_1678393978214/work/dist/qstylizer-0.2.2-py2.py3-none-any.whl |
||||
qt6-applications==6.4.3.2.3 |
||||
qt6-tools==6.4.3.1.3 |
||||
QtAwesome @ file:///Users/ec2-user/ci_py311/qtawesome_1678393953815/work |
||||
qtconsole @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_dexq2hi2gu/croot/qtconsole_1681394223590/work |
||||
QtPy @ file:///Users/ec2-user/ci_py311/qtpy_1678322936834/work |
||||
queuelib==1.5.0 |
||||
RandomWords==0.4.0 |
||||
rdflib==7.0.0 |
||||
redis==5.2.0 |
||||
referencing==0.36.2 |
||||
regex @ file:///Users/ec2-user/ci_py311/regex_1678394018661/work |
||||
reportlab==4.0.6 |
||||
requests==2.32.3 |
||||
requests-file @ file:///Users/ktietz/demo/mc3/conda-bld/requests-file_1629455781986/work |
||||
requests-toolbelt==1.0.0 |
||||
rfc3339-validator @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_07a1ken4gz/croot/rfc3339-validator_1683077050666/work |
||||
rfc3986-validator @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_6dzvsqx89i/croot/rfc3986-validator_1683059150431/work |
||||
rich==13.5.2 |
||||
rlp==4.0.1 |
||||
rope @ file:///Users/ec2-user/ci_py311/rope_1678379265159/work |
||||
rpds-py==0.25.1 |
||||
rstream==0.30.0 |
||||
Rtree @ file:///Users/ec2-user/ci_py311/rtree_1678394103092/work |
||||
ruamel-yaml-conda @ file:///Users/ec2-user/ci_py311/ruamel_yaml_1678394125333/work |
||||
ruamel.yaml @ file:///Users/ec2-user/ci_py311/ruamel.yaml_1678379291841/work |
||||
rumps==0.4.0 |
||||
s3fs @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_3dy0qlp99f/croot/s3fs_1680018510125/work |
||||
s3transfer @ file:///Users/ec2-user/ci_py311/s3transfer_1678324574832/work |
||||
sacremoses @ file:///tmp/build/80754af9/sacremoses_1633107328213/work |
||||
scapy==2.5.0 |
||||
scikit-image @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_3fh5dyitqb/croot/scikit-image_1682530834592/work |
||||
scikit-learn @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_506rr4lm7n/croot/scikit-learn_1684954727383/work |
||||
scipy==1.10.1 |
||||
Scrapy @ file:///Users/ec2-user/ci_py311/scrapy_1678422467931/work |
||||
seaborn @ file:///Users/ec2-user/ci_py311/seaborn_1678394152964/work |
||||
selenium==4.18.1 |
||||
selenium-wire==5.1.0 |
||||
Send2Trash @ file:///tmp/build/80754af9/send2trash_1632406701022/work |
||||
service-identity @ file:///Users/ktietz/demo/mc3/conda-bld/service_identity_1629460757137/work |
||||
sh==1.14.3 |
||||
simple-websocket==1.1.0 |
||||
simplejson==3.19.2 |
||||
sip @ file:///Users/ec2-user/ci_py311/sip_1678318421743/work |
||||
six @ file:///tmp/build/80754af9/six_1644875935023/work |
||||
smart-open @ file:///Users/ec2-user/ci_py311/smart_open_1678389689993/work |
||||
sniffio==1.3.0 |
||||
snowballstemmer @ file:///tmp/build/80754af9/snowballstemmer_1637937080595/work |
||||
socksio==1.0.0 |
||||
solders==0.25.0 |
||||
sortedcontainers @ file:///tmp/build/80754af9/sortedcontainers_1623949099177/work |
||||
soupsieve==2.8 |
||||
Sphinx @ file:///Users/ec2-user/ci_py311/sphinx_1678389735529/work |
||||
sphinxcontrib-applehelp @ file:///home/ktietz/src/ci/sphinxcontrib-applehelp_1611920841464/work |
||||
sphinxcontrib-devhelp @ file:///home/ktietz/src/ci/sphinxcontrib-devhelp_1611920923094/work |
||||
sphinxcontrib-htmlhelp @ file:///tmp/build/80754af9/sphinxcontrib-htmlhelp_1623945626792/work |
||||
sphinxcontrib-jsmath @ file:///home/ktietz/src/ci/sphinxcontrib-jsmath_1611920942228/work |
||||
sphinxcontrib-qthelp @ file:///home/ktietz/src/ci/sphinxcontrib-qthelp_1611921055322/work |
||||
sphinxcontrib-serializinghtml @ file:///tmp/build/80754af9/sphinxcontrib-serializinghtml_1624451540180/work |
||||
spyder @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_b93e0at0ak/croot/spyder_1681934083239/work |
||||
spyder-kernels @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_30ws3nleek/croot/spyder-kernels_1681307303955/work |
||||
SQLAlchemy @ file:///Users/ec2-user/ci_py311/sqlalchemy_1678379321154/work |
||||
stack-data @ file:///opt/conda/conda-bld/stack_data_1646927590127/work |
||||
starlette==0.27.0 |
||||
statsmodels @ file:///Users/ec2-user/ci_py311/statsmodels_1678394299954/work |
||||
supervisor==4.2.5 |
||||
svgwrite==1.4.3 |
||||
sympy @ file:///Users/ec2-user/ci_py311_2/sympy_1679338337660/work |
||||
tables @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_ccbzs9wm7e/croot/pytables_1685123223946/work |
||||
tabulate @ file:///Users/ec2-user/ci_py311/tabulate_1678423547338/work |
||||
TBB==0.2 |
||||
tblib @ file:///Users/ktietz/demo/mc3/conda-bld/tblib_1629402031467/work |
||||
tenacity==8.2.3 |
||||
termcolor==2.5.0 |
||||
terminado @ file:///Users/ec2-user/ci_py311/terminado_1678317735543/work |
||||
text-unidecode @ file:///Users/ktietz/demo/mc3/conda-bld/text-unidecode_1629401354553/work |
||||
textdistance @ file:///tmp/build/80754af9/textdistance_1612461398012/work |
||||
threadpoolctl @ file:///Users/ktietz/demo/mc3/conda-bld/threadpoolctl_1629802263681/work |
||||
three-merge @ file:///tmp/build/80754af9/three-merge_1607553261110/work |
||||
tifffile @ file:///tmp/build/80754af9/tifffile_1627275862826/work |
||||
time-machine==2.16.0 |
||||
tinycss2 @ file:///Users/ec2-user/ci_py311/tinycss2_1678317366076/work |
||||
tinydb==4.8.2 |
||||
tldextract==5.1.3 |
||||
toml @ file:///tmp/build/80754af9/toml_1616166611790/work |
||||
tomli @ file:///Users/ec2-user/ci_py311/tomli_1678315243316/work |
||||
tomlkit @ file:///Users/ec2-user/ci_py311/tomlkit_1678317388739/work |
||||
toolz @ file:///Users/ec2-user/ci_py311/toolz_1678323009669/work |
||||
torch==2.0.0 |
||||
torchvision==0.15 |
||||
tornado @ file:///Users/ec2-user/ci_py311/tornado_1678316833426/work |
||||
tqdm==4.67.1 |
||||
traitlets @ file:///Users/ec2-user/ci_py311/traitlets_1678316097905/work |
||||
traits==6.3.2 |
||||
transformers @ file:///tmp/build/80754af9/transformers_1633098115425/work |
||||
trio==0.24.0 |
||||
trio-websocket==0.11.1 |
||||
tushare==1.2.89 |
||||
twikit==2.3.3 |
||||
Twisted @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_3cf4rqmb9n/croot/twisted_1683796897214/work |
||||
typing-inspect==0.9.0 |
||||
typing-inspection==0.4.1 |
||||
typing-utils==0.1.0 |
||||
typing_extensions==4.12.2 |
||||
tzdata==2024.2 |
||||
tzlocal==5.3.1 |
||||
uc-micro-py @ file:///Users/ec2-user/ci_py311/uc-micro-py_1678394873457/work |
||||
ujson @ file:///Users/ec2-user/ci_py311/ujson_1678325349324/work |
||||
Unidecode @ file:///tmp/build/80754af9/unidecode_1614712377438/work |
||||
uri-template==1.3.0 |
||||
urllib3==1.26.18 |
||||
uvicorn==0.24.0 |
||||
uvloop==0.17.0 |
||||
vbuild==0.8.2 |
||||
virtualenv==20.27.0 |
||||
w3lib @ file:///Users/ktietz/demo/mc3/conda-bld/w3lib_1629359764703/work |
||||
watchdog @ file:///Users/ec2-user/ci_py311/watchdog_1678395046770/work |
||||
watchfiles==0.19.0 |
||||
wcwidth @ file:///Users/ktietz/demo/mc3/conda-bld/wcwidth_1629357192024/work |
||||
web3==6.17.2 |
||||
webcolors==24.11.1 |
||||
webencodings==0.5.1 |
||||
websocket-client==0.57.0 |
||||
websockets==12.0 |
||||
webvtt-py==0.5.1 |
||||
Werkzeug @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_fegt3z60s3/croot/werkzeug_1679489762631/work |
||||
whatthepatch @ file:///Users/ec2-user/ci_py311/whatthepatch_1678379478749/work |
||||
widgetsnbextension @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_8feupjw2ld/croot/widgetsnbextension_1679313870305/work |
||||
wrapt @ file:///Users/ec2-user/ci_py311/wrapt_1678323111850/work |
||||
wsproto==1.2.0 |
||||
wurlitzer @ file:///Users/ec2-user/ci_py311/wurlitzer_1678390004531/work |
||||
xarray @ file:///Users/ec2-user/ci_py311/xarray_1678395099624/work |
||||
XlsxWriter==3.1.2 |
||||
xlwings @ file:///Users/ec2-user/ci_py311_2/xlwings_1679338568565/work |
||||
xyzservices @ file:///Users/ec2-user/ci_py311/xyzservices_1678325391212/work |
||||
y-py @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_7dvnlnkj12/croot/y-py_1683555629284/work |
||||
yapf @ file:///tmp/build/80754af9/yapf_1615749224965/work |
||||
yarl==1.18.3 |
||||
you-get==0.4.1730 |
||||
ypy-websocket @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_75t89iv95n/croot/ypy-websocket_1684171758794/work |
||||
zict @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_59schmcson/croot/zict_1682698747213/work |
||||
zipp @ file:///Users/ec2-user/ci_py311/zipp_1678318061389/work |
||||
zope.interface @ file:///Users/ec2-user/ci_py311/zope.interface_1678379536727/work |
||||
zstandard @ file:///Users/ec2-user/ci_py311_2/zstandard_1679338593428/work |
||||
@ -1,289 +0,0 @@ |
||||
[ |
||||
{ |
||||
"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 |
||||
} |
||||
] |
||||
@ -1,524 +0,0 @@ |
||||
[ |
||||
{ |
||||
"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 |
||||
} |
||||
} |
||||
] |
||||
@ -1,82 +0,0 @@ |
||||
[ |
||||
{ |
||||
"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 |
||||
} |
||||
] |
||||
@ -1,12 +0,0 @@ |
||||
[ |
||||
{ |
||||
"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,60 @@ |
||||
# -*- coding: utf-8 -*- |
||||
"""Alpha表达式服务""" |
||||
|
||||
import time |
||||
import httpx |
||||
from typing import List, Dict, Any |
||||
from config.settings import settings |
||||
|
||||
|
||||
class AlphaService: |
||||
"""Alpha表达式服务类""" |
||||
|
||||
def __init__(self, client: httpx.Client): |
||||
self.client = client |
||||
|
||||
def simulate_alpha(self, expression: str) -> Dict[str, Any]: |
||||
"""模拟单个Alpha表达式""" |
||||
simulation_data = { |
||||
'type': 'REGULAR', |
||||
'settings': settings.SIMULATION_SETTINGS, |
||||
'regular': expression |
||||
} |
||||
|
||||
sim_resp = self.client.post(f'{settings.BRAIN_API_URL}/simulations', json=simulation_data) |
||||
print(f"模拟提交状态: {sim_resp.status_code}") |
||||
|
||||
if 'location' not in sim_resp.headers: |
||||
return {"status": "err", "message": "No location header in response"} |
||||
|
||||
sim_progress_url = sim_resp.headers['location'] |
||||
return self._wait_for_simulation_result(sim_progress_url) |
||||
|
||||
def _wait_for_simulation_result(self, progress_url: str) -> Dict[str, Any]: |
||||
"""等待模拟结果""" |
||||
while True: |
||||
sim_progress_resp = self.client.get(progress_url) |
||||
retry_after_sec = float(sim_progress_resp.headers.get("Retry-After", 0)) |
||||
|
||||
if retry_after_sec == 0: |
||||
break |
||||
|
||||
if sim_progress_resp.json(): |
||||
result = sim_progress_resp.json() |
||||
progress = result.get('progress', 0) |
||||
print(f"模拟进度: {float(progress) * 100}%") |
||||
|
||||
print(f"等待 {retry_after_sec} 秒...") |
||||
time.sleep(retry_after_sec) |
||||
|
||||
result_data = sim_progress_resp.json() |
||||
|
||||
if result_data.get("status") == "ERROR": |
||||
error_message = result_data.get("message", "未知错误") |
||||
print(f"因子模拟失败: {error_message}") |
||||
return {"status": "err", "message": error_message} |
||||
|
||||
alpha_id = result_data.get("alpha") |
||||
print(f"生成的Alpha ID: {alpha_id}") |
||||
|
||||
return {"status": "ok", "alpha_id": alpha_id} |
||||
@ -0,0 +1,57 @@ |
||||
# -*- coding: utf-8 -*- |
||||
"""认证服务""" |
||||
|
||||
import os |
||||
import httpx |
||||
from httpx import BasicAuth |
||||
from typing import Tuple, Dict, Any |
||||
from config.settings import settings |
||||
from models.entities import TokenInfo |
||||
|
||||
|
||||
class AuthService: |
||||
"""认证服务类""" |
||||
|
||||
def __init__(self): |
||||
self.credentials_file = settings.credentials_file |
||||
|
||||
def load_credentials(self) -> Tuple[str, str]: |
||||
"""加载凭证""" |
||||
if not os.path.exists(self.credentials_file): |
||||
self._create_credentials_file() |
||||
|
||||
with open(self.credentials_file, 'r', encoding='utf-8') as f: |
||||
credentials = eval(f.read()) |
||||
return credentials[0], credentials[1] |
||||
|
||||
def _create_credentials_file(self) -> None: |
||||
"""创建凭证文件""" |
||||
print("未找到 account.txt 文件") |
||||
with open(self.credentials_file, 'w', encoding='utf-8') as f: |
||||
f.write("") |
||||
print("account.txt 文件已创建,请填写账号密码, 格式: ['username', 'password']") |
||||
exit(1) |
||||
|
||||
def login(self, client: httpx.Client) -> TokenInfo: |
||||
"""登录并获取token""" |
||||
username, password = self.load_credentials() |
||||
|
||||
# 设置 BasicAuth |
||||
client.auth = BasicAuth(username, password) |
||||
|
||||
response = client.post(f'{settings.BRAIN_API_URL}/authentication') |
||||
print(f"登录状态: {response.status_code}") |
||||
|
||||
if response.status_code == 201: |
||||
login_data = response.json() |
||||
print(f"登录成功!: {login_data}") |
||||
return TokenInfo( |
||||
token=login_data['token'], |
||||
expiry=int(login_data['token']['expiry']) |
||||
) |
||||
elif response.status_code == 429: |
||||
print("API rate limit exceeded") |
||||
exit(1) |
||||
else: |
||||
print(f"登录失败: {response.json()}") |
||||
raise Exception(f"登录失败: {response.json()}") |
||||
@ -0,0 +1,27 @@ |
||||
# -*- coding: utf-8 -*- |
||||
"""通知服务""" |
||||
|
||||
import httpx |
||||
from datetime import datetime |
||||
from config.settings import settings |
||||
|
||||
|
||||
class NotificationService: |
||||
"""通知服务类""" |
||||
|
||||
@staticmethod |
||||
def send_to_gotify(success_count: int, fail_count: int) -> None: |
||||
"""发送结果到Gotify""" |
||||
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') |
||||
text = f"总计: 成功 {success_count} 个, 失败 {fail_count} 个\n\n完成时间: {now}" |
||||
title = f"alpha模拟结果 时间: {now}" |
||||
|
||||
try: |
||||
resp = httpx.post( |
||||
settings.GOTIFY_URL, |
||||
json={'title': title, 'message': text}, |
||||
timeout=10 |
||||
) |
||||
print("通知发送成功") |
||||
except Exception as e: |
||||
print(f"通知发送失败: {e}") |
||||
@ -1,4 +0,0 @@ |
||||
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) |
||||
@ -1,9 +0,0 @@ |
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
工具模块 - 包含各种工具函数 |
||||
""" |
||||
|
||||
from .file_utils import load_alpha_list, save_results_to_file |
||||
from .time_utils import format_time |
||||
|
||||
__all__ = ['load_alpha_list', 'save_results_to_file', 'format_time'] |
||||
@ -1,84 +0,0 @@ |
||||
# -*- coding: utf-8 -*- |
||||
import os |
||||
import json |
||||
import time |
||||
from typing import List, Any |
||||
|
||||
|
||||
def load_alpha_list(file_path: str) -> List[str]: |
||||
"""从文件加载Alpha因子列表""" |
||||
if not os.path.exists(file_path): |
||||
print(f"{file_path} 文件不存在") |
||||
with open(file_path, 'w', encoding='utf-8') as file: |
||||
file.write("") |
||||
print(f"已创建 {file_path} 文件, 请添加因子后重新运行, 一行一个因子") |
||||
return [] |
||||
|
||||
with open(file_path, 'r', encoding='utf-8') as file: |
||||
alpha_list = [line.strip() for line in file if line.strip()] |
||||
|
||||
return alpha_list |
||||
|
||||
|
||||
def save_results_to_file(results: List[Any], result_dir: str = 'result') -> str: |
||||
"""保存结果到文件""" |
||||
# 转换为可序列化的格式 |
||||
serializable_results = [] |
||||
for result in results: |
||||
if hasattr(result, '__dict__'): |
||||
# 如果是dataclass对象,转换为字典 |
||||
result_dict = result.__dict__.copy() |
||||
else: |
||||
# 如果是字典 |
||||
result_dict = result.copy() |
||||
|
||||
# 处理时间消耗 |
||||
if 'time_consuming' in result_dict: |
||||
result_dict['time_consuming'] = round(result_dict['time_consuming'], 2) |
||||
|
||||
# 只需要确保所有浮点数精度一致 |
||||
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) |
||||
|
||||
# 确保结果目录存在 |
||||
if not os.path.exists(result_dir): |
||||
os.makedirs(result_dir) |
||||
|
||||
result_name = f"{result_dir}/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}") |
||||
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}") |
||||
@ -0,0 +1,23 @@ |
||||
# -*- coding: utf-8 -*- |
||||
"""工具函数""" |
||||
|
||||
import time |
||||
from typing import Callable, Any |
||||
|
||||
|
||||
def retry_on_exception(max_retries: int = 3, delay: float = 5.0) -> Callable: |
||||
"""异常重试装饰器""" |
||||
def decorator(func: Callable) -> Callable: |
||||
def wrapper(*args, **kwargs) -> Any: |
||||
for attempt in range(max_retries): |
||||
try: |
||||
return func(*args, **kwargs) |
||||
except Exception as e: |
||||
if attempt == max_retries - 1: |
||||
raise e |
||||
print(f"尝试 {attempt + 1}/{max_retries} 失败: {e}") |
||||
print(f"{delay}秒后重试...") |
||||
time.sleep(delay) |
||||
return None |
||||
return wrapper |
||||
return decorator |
||||
@ -1,9 +0,0 @@ |
||||
# -*- coding: utf-8 -*- |
||||
def format_time(seconds: float) -> str: |
||||
"""将秒数格式化为 xx分xx秒 格式""" |
||||
if seconds < 60: |
||||
return f"{seconds:.2f}秒" |
||||
else: |
||||
minutes = int(seconds // 60) |
||||
remaining_seconds = seconds % 60 |
||||
return f"{minutes}分{remaining_seconds:.2f}秒" |
||||
Loading…
Reference in new issue