cnhkmcp 2.1.2__py3-none-any.whl → 2.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/METADATA +1 -1
- cnhkmcp-2.1.3.dist-info/RECORD +6 -0
- cnhkmcp-2.1.3.dist-info/top_level.txt +1 -0
- cnhkmcp/__init__.py +0 -125
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/README.md +0 -38
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/ace.log +0 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/config.json +0 -6
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/ace_lib.py +0 -1510
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/fetch_all_datasets.py +0 -157
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/fetch_all_documentation.py +0 -132
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/fetch_all_operators.py +0 -99
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/helpful_functions.py +0 -180
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/icon.ico +0 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/icon.png +0 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/test.txt +0 -1
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/main.py +0 -576
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/process_knowledge_base.py +0 -281
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/rag_engine.py +0 -408
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/requirements.txt +0 -7
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/run.bat +0 -3
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242//321/211/320/266/320/246/321/206/320/274/320/261/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +0 -265
- cnhkmcp/untracked/APP/.gitignore +0 -32
- cnhkmcp/untracked/APP/MODULAR_STRUCTURE.md +0 -112
- cnhkmcp/untracked/APP/README.md +0 -309
- cnhkmcp/untracked/APP/Tranformer/Transformer.py +0 -4985
- cnhkmcp/untracked/APP/Tranformer/ace.log +0 -0
- cnhkmcp/untracked/APP/Tranformer/ace_lib.py +0 -1510
- cnhkmcp/untracked/APP/Tranformer/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates.json +0 -2421
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates_/321/207/320/264/342/225/221/321/204/342/225/233/320/233.json +0 -654
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_error.json +0 -1034
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_success.json +0 -444
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_/321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/320/237/320/277/321/207/320/253/342/224/244/321/206/320/236/320/265/321/210/342/225/234/342/225/234/321/205/320/225/320/265Machine_lib.json +0 -22
- cnhkmcp/untracked/APP/Tranformer/parsetab.py +0 -60
- cnhkmcp/untracked/APP/Tranformer/template_summary.txt +0 -3182
- cnhkmcp/untracked/APP/Tranformer/transformer_config.json +0 -7
- cnhkmcp/untracked/APP/Tranformer/validator.py +0 -889
- cnhkmcp/untracked/APP/ace.log +0 -69
- cnhkmcp/untracked/APP/ace_lib.py +0 -1510
- cnhkmcp/untracked/APP/blueprints/__init__.py +0 -6
- cnhkmcp/untracked/APP/blueprints/feature_engineering.py +0 -347
- cnhkmcp/untracked/APP/blueprints/idea_house.py +0 -221
- cnhkmcp/untracked/APP/blueprints/inspiration_house.py +0 -432
- cnhkmcp/untracked/APP/blueprints/paper_analysis.py +0 -570
- cnhkmcp/untracked/APP/custom_templates/templates.json +0 -1257
- cnhkmcp/untracked/APP/give_me_idea/BRAIN_Alpha_Template_Expert_SystemPrompt.md +0 -400
- cnhkmcp/untracked/APP/give_me_idea/ace_lib.py +0 -1510
- cnhkmcp/untracked/APP/give_me_idea/alpha_data_specific_template_master.py +0 -252
- cnhkmcp/untracked/APP/give_me_idea/fetch_all_datasets.py +0 -157
- cnhkmcp/untracked/APP/give_me_idea/fetch_all_operators.py +0 -99
- cnhkmcp/untracked/APP/give_me_idea/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP/give_me_idea/what_is_Alpha_template.md +0 -11
- cnhkmcp/untracked/APP/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP/hkSimulator/ace_lib.py +0 -1497
- cnhkmcp/untracked/APP/hkSimulator/autosimulator.py +0 -447
- cnhkmcp/untracked/APP/hkSimulator/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP/mirror_config.txt +0 -20
- cnhkmcp/untracked/APP/operaters.csv +0 -129
- cnhkmcp/untracked/APP/requirements.txt +0 -53
- cnhkmcp/untracked/APP/run_app.bat +0 -28
- cnhkmcp/untracked/APP/run_app.sh +0 -34
- cnhkmcp/untracked/APP/setup_tsinghua.bat +0 -39
- cnhkmcp/untracked/APP/setup_tsinghua.sh +0 -43
- cnhkmcp/untracked/APP/simulator/alpha_submitter.py +0 -404
- cnhkmcp/untracked/APP/simulator/simulator_wqb.py +0 -618
- cnhkmcp/untracked/APP/ssrn-3332513.pdf +6 -109201
- cnhkmcp/untracked/APP/static/brain.js +0 -589
- cnhkmcp/untracked/APP/static/decoder.js +0 -1540
- cnhkmcp/untracked/APP/static/feature_engineering.js +0 -1729
- cnhkmcp/untracked/APP/static/idea_house.js +0 -937
- cnhkmcp/untracked/APP/static/inspiration.js +0 -465
- cnhkmcp/untracked/APP/static/inspiration_house.js +0 -868
- cnhkmcp/untracked/APP/static/paper_analysis.js +0 -390
- cnhkmcp/untracked/APP/static/script.js +0 -3082
- cnhkmcp/untracked/APP/static/simulator.js +0 -597
- cnhkmcp/untracked/APP/static/styles.css +0 -3127
- cnhkmcp/untracked/APP/static/usage_widget.js +0 -508
- cnhkmcp/untracked/APP/templates/alpha_inspector.html +0 -511
- cnhkmcp/untracked/APP/templates/feature_engineering.html +0 -960
- cnhkmcp/untracked/APP/templates/idea_house.html +0 -564
- cnhkmcp/untracked/APP/templates/index.html +0 -932
- cnhkmcp/untracked/APP/templates/inspiration_house.html +0 -861
- cnhkmcp/untracked/APP/templates/paper_analysis.html +0 -91
- cnhkmcp/untracked/APP/templates/simulator.html +0 -343
- cnhkmcp/untracked/APP/templates/transformer_web.html +0 -580
- cnhkmcp/untracked/APP/usage.md +0 -351
- cnhkmcp/untracked/APP//321/207/342/225/235/320/250/321/205/320/230/320/226/321/204/342/225/225/320/220/321/211/320/221/320/243/321/206/320/261/320/265/ace_lib.py +0 -1510
- cnhkmcp/untracked/APP//321/207/342/225/235/320/250/321/205/320/230/320/226/321/204/342/225/225/320/220/321/211/320/221/320/243/321/206/320/261/320/265/brain_alpha_inspector.py +0 -712
- cnhkmcp/untracked/APP//321/207/342/225/235/320/250/321/205/320/230/320/226/321/204/342/225/225/320/220/321/211/320/221/320/243/321/206/320/261/320/265/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP//321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +0 -2456
- cnhkmcp/untracked/arXiv_API_Tool_Manual.md +0 -490
- cnhkmcp/untracked/arxiv_api.py +0 -229
- cnhkmcp/untracked/forum_functions.py +0 -998
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/forum_functions.py +0 -407
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/platform_functions.py +0 -2415
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/user_config.json +0 -31
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272//321/210/320/276/320/271AI/321/210/320/277/342/225/227/321/210/342/224/220/320/251/321/204/342/225/225/320/272/321/206/320/246/320/227/321/206/320/261/320/263/321/206/320/255/320/265/321/205/320/275/320/266/321/204/342/225/235/320/252/321/204/342/225/225/320/233/321/210/342/225/234/342/225/234/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270.md +0 -101
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272//321/211/320/225/320/235/321/207/342/225/234/320/276/321/205/320/231/320/235/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/230/320/241_/321/205/320/276/320/231/321/210/320/263/320/225/321/205/342/224/220/320/225/321/210/320/266/320/221/321/204/342/225/233/320/255/321/210/342/225/241/320/246/321/205/320/234/320/225.py +0 -190
- cnhkmcp/untracked/platform_functions.py +0 -2886
- cnhkmcp/untracked/sample_mcp_config.json +0 -11
- cnhkmcp/untracked/user_config.json +0 -31
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/320/237/320/222/321/210/320/220/320/223/321/206/320/246/320/227/321/206/320/261/320/263_BRAIN_Alpha_Test_Requirements_and_Tips.md +0 -202
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_Alpha_explaination_workflow.md +0 -56
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_BRAIN_6_Tips_Datafield_Exploration_Guide.md +0 -194
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_BRAIN_Alpha_Improvement_Workflow.md +0 -101
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_Dataset_Exploration_Expert_Manual.md +0 -436
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_daily_report_workflow.md +0 -128
- cnhkmcp/untracked//321/211/320/225/320/235/321/207/342/225/234/320/276/321/205/320/231/320/235/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/230/320/241_/321/205/320/276/320/231/321/210/320/263/320/225/321/205/342/224/220/320/225/321/210/320/266/320/221/321/204/342/225/233/320/255/321/210/342/225/241/320/246/321/205/320/234/320/225.py +0 -190
- cnhkmcp-2.1.2.dist-info/RECORD +0 -111
- cnhkmcp-2.1.2.dist-info/top_level.txt +0 -1
- {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/WHEEL +0 -0
- {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/entry_points.txt +0 -0
- {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,447 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
import subprocess
|
|
3
|
-
# --- Dependency Check & Auto-Install ---
|
|
4
|
-
required_imports = [
|
|
5
|
-
("getpass", None),
|
|
6
|
-
("json", None),
|
|
7
|
-
("logging", None),
|
|
8
|
-
("os", None),
|
|
9
|
-
("threading", None),
|
|
10
|
-
("time", None),
|
|
11
|
-
("functools", None),
|
|
12
|
-
("multiprocessing", None),
|
|
13
|
-
("pathlib", None),
|
|
14
|
-
("typing", None),
|
|
15
|
-
("urllib.parse", None),
|
|
16
|
-
("pandas", "pandas"),
|
|
17
|
-
("requests", "requests"),
|
|
18
|
-
("tqdm", "tqdm"),
|
|
19
|
-
("pandas.io.formats.style", "pandas"),
|
|
20
|
-
]
|
|
21
|
-
for mod, pipname in required_imports:
|
|
22
|
-
try:
|
|
23
|
-
if "." in mod:
|
|
24
|
-
__import__(mod.split(".")[0])
|
|
25
|
-
else:
|
|
26
|
-
__import__(mod)
|
|
27
|
-
except ImportError:
|
|
28
|
-
if pipname:
|
|
29
|
-
print(f"Installing missing package: {pipname}")
|
|
30
|
-
subprocess.check_call([sys.executable, "-m", "pip", "install", pipname])
|
|
31
|
-
else:
|
|
32
|
-
print(f"Module {mod} is a built-in or not installable via pip.")
|
|
33
|
-
# --- Script Description ---
|
|
34
|
-
"""
|
|
35
|
-
Autosimulator for WorldQuant BRAIN platform
|
|
36
|
-
- Timestamped logger
|
|
37
|
-
- Authentication with biometric check
|
|
38
|
-
- User-specified alpha JSON input
|
|
39
|
-
- Single/multi simulation mode
|
|
40
|
-
- Simulation worker: sends jobs, retries, saves locations
|
|
41
|
-
- Result worker: fetches results, saves to JSON
|
|
42
|
-
"""
|
|
43
|
-
import os
|
|
44
|
-
import sys
|
|
45
|
-
import time
|
|
46
|
-
import json
|
|
47
|
-
import threading
|
|
48
|
-
import logging
|
|
49
|
-
from datetime import datetime
|
|
50
|
-
from pathlib import Path
|
|
51
|
-
import requests
|
|
52
|
-
import getpass
|
|
53
|
-
|
|
54
|
-
# Platform specific imports
|
|
55
|
-
if sys.platform == 'win32':
|
|
56
|
-
import msvcrt
|
|
57
|
-
else:
|
|
58
|
-
import tty
|
|
59
|
-
import termios
|
|
60
|
-
from ace_lib import (
|
|
61
|
-
check_session_and_relogin,
|
|
62
|
-
simulate_single_alpha,
|
|
63
|
-
simulate_multi_alpha,
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
# --- Logger Setup ---
|
|
67
|
-
def setup_logger():
|
|
68
|
-
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
|
69
|
-
log_filename = f'autosim_{timestamp}.log'
|
|
70
|
-
logger = logging.getLogger(f'autosim_{timestamp}')
|
|
71
|
-
logger.setLevel(logging.DEBUG)
|
|
72
|
-
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
|
73
|
-
fh = logging.FileHandler(log_filename)
|
|
74
|
-
fh.setFormatter(formatter)
|
|
75
|
-
logger.addHandler(fh)
|
|
76
|
-
ch = logging.StreamHandler()
|
|
77
|
-
ch.setFormatter(formatter)
|
|
78
|
-
logger.addHandler(ch)
|
|
79
|
-
return logger, log_filename
|
|
80
|
-
|
|
81
|
-
logger, log_filename = setup_logger()
|
|
82
|
-
|
|
83
|
-
# --- Authentication ---
|
|
84
|
-
def check_session_timeout(s):
|
|
85
|
-
"""
|
|
86
|
-
Check if the current session has timed out.
|
|
87
|
-
|
|
88
|
-
Args:
|
|
89
|
-
s (SingleSession): The current session object.
|
|
90
|
-
|
|
91
|
-
Returns:
|
|
92
|
-
int: The number of seconds until the session expires, or 0 if the session has expired or an error occurred.
|
|
93
|
-
"""
|
|
94
|
-
brain_api_url = os.environ.get("BRAIN_API_URL", "https://api.worldquantbrain.com")
|
|
95
|
-
authentication_url = brain_api_url + "/authentication"
|
|
96
|
-
try:
|
|
97
|
-
result = s.get(authentication_url).json()["token"]["expiry"]
|
|
98
|
-
logger.debug(f"Session (ID: {id(s)}) timeout check result: {result}")
|
|
99
|
-
return result
|
|
100
|
-
except Exception:
|
|
101
|
-
logger.error(f"Session timeout check failed for session (ID: {id(s)})")
|
|
102
|
-
return 0
|
|
103
|
-
def get_credentials():
|
|
104
|
-
email = input("Email: ").strip()
|
|
105
|
-
print("Password: ", end='', flush=True)
|
|
106
|
-
password = []
|
|
107
|
-
|
|
108
|
-
try:
|
|
109
|
-
if sys.platform == 'win32':
|
|
110
|
-
# Windows: Use msvcrt.getch()
|
|
111
|
-
while True:
|
|
112
|
-
char = msvcrt.getch()
|
|
113
|
-
|
|
114
|
-
# Handle Enter key
|
|
115
|
-
if char in [b'\r', b'\n']:
|
|
116
|
-
print() # New line
|
|
117
|
-
break
|
|
118
|
-
|
|
119
|
-
# Handle Backspace
|
|
120
|
-
elif char == b'\x08': # Backspace
|
|
121
|
-
if password:
|
|
122
|
-
password.pop()
|
|
123
|
-
# Move cursor back, print space, move cursor back again
|
|
124
|
-
print('\b \b', end='', flush=True)
|
|
125
|
-
|
|
126
|
-
# Handle Ctrl+C
|
|
127
|
-
elif char == b'\x03': # Ctrl+C
|
|
128
|
-
print()
|
|
129
|
-
raise KeyboardInterrupt
|
|
130
|
-
|
|
131
|
-
# Handle printable characters (ASCII)
|
|
132
|
-
elif 32 <= ord(char) <= 126: # Printable ASCII range
|
|
133
|
-
password.append(char.decode('ascii'))
|
|
134
|
-
print('*', end='', flush=True)
|
|
135
|
-
|
|
136
|
-
# Handle extended characters
|
|
137
|
-
else:
|
|
138
|
-
try:
|
|
139
|
-
decoded_char = char.decode('utf-8')
|
|
140
|
-
if decoded_char.isprintable():
|
|
141
|
-
password.append(decoded_char)
|
|
142
|
-
print('*', end='', flush=True)
|
|
143
|
-
except UnicodeDecodeError:
|
|
144
|
-
continue
|
|
145
|
-
else:
|
|
146
|
-
# Unix/macOS: Use tty and termios
|
|
147
|
-
fd = sys.stdin.fileno()
|
|
148
|
-
old_settings = termios.tcgetattr(fd)
|
|
149
|
-
try:
|
|
150
|
-
tty.setraw(fd)
|
|
151
|
-
while True:
|
|
152
|
-
char = sys.stdin.read(1)
|
|
153
|
-
|
|
154
|
-
# Handle Enter key
|
|
155
|
-
if char in ['\r', '\n']:
|
|
156
|
-
print('\r\n', end='', flush=True)
|
|
157
|
-
break
|
|
158
|
-
|
|
159
|
-
# Handle Backspace
|
|
160
|
-
elif char in ['\x7f', '\x08']:
|
|
161
|
-
if password:
|
|
162
|
-
password.pop()
|
|
163
|
-
print('\b \b', end='', flush=True)
|
|
164
|
-
|
|
165
|
-
# Handle Ctrl+C
|
|
166
|
-
elif char == '\x03':
|
|
167
|
-
print('\r\n', end='', flush=True)
|
|
168
|
-
raise KeyboardInterrupt
|
|
169
|
-
|
|
170
|
-
# Handle printable characters
|
|
171
|
-
elif char.isprintable():
|
|
172
|
-
password.append(char)
|
|
173
|
-
print('*', end='', flush=True)
|
|
174
|
-
finally:
|
|
175
|
-
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
176
|
-
|
|
177
|
-
except Exception as e:
|
|
178
|
-
# Fallback to getpass
|
|
179
|
-
print(f"\nError reading password: {e}")
|
|
180
|
-
print("Falling back to getpass...")
|
|
181
|
-
return (email, getpass.getpass())
|
|
182
|
-
|
|
183
|
-
return (email, ''.join(password))
|
|
184
|
-
|
|
185
|
-
def authenticate():
|
|
186
|
-
from ace_lib import SingleSession
|
|
187
|
-
session = SingleSession()
|
|
188
|
-
session.auth = get_credentials()
|
|
189
|
-
brain_api_url = os.environ.get("BRAIN_API_URL", "https://api.worldquantbrain.com")
|
|
190
|
-
r = session.post(brain_api_url + "/authentication")
|
|
191
|
-
logger.debug(f"New session created (ID: {id(session)}) with authentication response: {r.status_code}, {r.json()}")
|
|
192
|
-
if r.status_code == requests.status_codes.codes.unauthorized:
|
|
193
|
-
if r.headers.get("WWW-Authenticate") == "persona":
|
|
194
|
-
print(
|
|
195
|
-
"Complete biometrics authentication and press any key to continue: \n"
|
|
196
|
-
+ r.url + "/persona?inquiry=" + r.headers.get("Location", "")
|
|
197
|
-
+ "\n"
|
|
198
|
-
)
|
|
199
|
-
input()
|
|
200
|
-
session.post(r.headers.get("Location", r.url))
|
|
201
|
-
while True:
|
|
202
|
-
if session.post(r.headers.get("Location", r.url)).status_code != 201:
|
|
203
|
-
input(
|
|
204
|
-
"Biometrics authentication is not complete. Please try again and press any key when completed \n"
|
|
205
|
-
)
|
|
206
|
-
else:
|
|
207
|
-
break
|
|
208
|
-
else:
|
|
209
|
-
logger.error("\nIncorrect email or password\n")
|
|
210
|
-
return authenticate()
|
|
211
|
-
return session
|
|
212
|
-
|
|
213
|
-
# --- User Input ---
|
|
214
|
-
MASTER_LOG_PATH = "autosim_master_log.json"
|
|
215
|
-
|
|
216
|
-
def update_master_log(input_json_path, latest_index):
|
|
217
|
-
"""
|
|
218
|
-
Update the master log file with the latest successful index for the given input file name.
|
|
219
|
-
"""
|
|
220
|
-
import os, json
|
|
221
|
-
file_name = os.path.basename(input_json_path)
|
|
222
|
-
log_data = {}
|
|
223
|
-
# Read existing log if present
|
|
224
|
-
if os.path.exists(MASTER_LOG_PATH):
|
|
225
|
-
try:
|
|
226
|
-
with open(MASTER_LOG_PATH, "r", encoding="utf-8") as f:
|
|
227
|
-
log_data = json.load(f)
|
|
228
|
-
except Exception:
|
|
229
|
-
log_data = {}
|
|
230
|
-
# Update with latest index
|
|
231
|
-
log_data[file_name] = latest_index
|
|
232
|
-
# Atomic write
|
|
233
|
-
tmp_path = MASTER_LOG_PATH + ".tmp"
|
|
234
|
-
with open(tmp_path, "w", encoding="utf-8") as f:
|
|
235
|
-
json.dump(log_data, f, indent=2)
|
|
236
|
-
os.replace(tmp_path, MASTER_LOG_PATH)
|
|
237
|
-
def get_user_json():
|
|
238
|
-
import re
|
|
239
|
-
while True:
|
|
240
|
-
raw_path = input('Enter path to alpha JSON file: ').strip()
|
|
241
|
-
json_path = re.sub(r'^["\']+|["\']+$', '', raw_path.strip())
|
|
242
|
-
if os.path.exists(json_path):
|
|
243
|
-
try:
|
|
244
|
-
with open(json_path, 'r', encoding='utf-8') as f:
|
|
245
|
-
alpha_list = json.load(f)
|
|
246
|
-
# Check master log for previous progress
|
|
247
|
-
file_name = os.path.basename(json_path)
|
|
248
|
-
start_index = 0
|
|
249
|
-
if os.path.exists(MASTER_LOG_PATH):
|
|
250
|
-
try:
|
|
251
|
-
with open(MASTER_LOG_PATH, 'r', encoding='utf-8') as logf:
|
|
252
|
-
log_data = json.load(logf)
|
|
253
|
-
if file_name in log_data:
|
|
254
|
-
last_index = log_data[file_name]
|
|
255
|
-
print(f'Last time you simulated to position {last_index}.')
|
|
256
|
-
resp = input(f'Do you want to start from {last_index + 1}? (Y/n) Or enter another starting index: ').strip()
|
|
257
|
-
if resp.lower() in ['', 'y', 'yes']:
|
|
258
|
-
start_index = last_index + 1
|
|
259
|
-
elif resp.isdigit():
|
|
260
|
-
start_index = int(resp)
|
|
261
|
-
else:
|
|
262
|
-
print('Invalid input, starting from 0.')
|
|
263
|
-
start_index = 0
|
|
264
|
-
except Exception:
|
|
265
|
-
pass
|
|
266
|
-
# Slice alpha_list to start from chosen index
|
|
267
|
-
class AlphaList(list):
|
|
268
|
-
pass
|
|
269
|
-
alpha_list = AlphaList(alpha_list[start_index:])
|
|
270
|
-
alpha_list._start_index = start_index
|
|
271
|
-
return alpha_list, json_path
|
|
272
|
-
except Exception as e:
|
|
273
|
-
logger.error(f'Error reading JSON file: {e}')
|
|
274
|
-
else:
|
|
275
|
-
logger.error(f'JSON file not found: {json_path}')
|
|
276
|
-
print('Please enter a valid path to your alpha JSON file.')
|
|
277
|
-
|
|
278
|
-
def get_simulation_mode():
|
|
279
|
-
mode = input('Select simulation mode (single/multi): ').strip().lower()
|
|
280
|
-
if mode not in ['single', 'multi']:
|
|
281
|
-
logger.error('Invalid mode. Choose "single" or "multi".')
|
|
282
|
-
sys.exit(1)
|
|
283
|
-
batch_size = None
|
|
284
|
-
if mode == 'multi':
|
|
285
|
-
while True:
|
|
286
|
-
try:
|
|
287
|
-
batch_size = int(input('Enter number of elements per multi-simulation batch (2-10): ').strip())
|
|
288
|
-
if 2 <= batch_size <= 10:
|
|
289
|
-
break
|
|
290
|
-
else:
|
|
291
|
-
print('Batch size must be between 2 and 10.')
|
|
292
|
-
except Exception:
|
|
293
|
-
print('Please enter a valid integer between 2 and 10.')
|
|
294
|
-
return mode, batch_size
|
|
295
|
-
|
|
296
|
-
def get_retry_timeout():
|
|
297
|
-
try:
|
|
298
|
-
timeout = int(input('Enter retry timeout in seconds (default 60): ').strip())
|
|
299
|
-
if timeout < 1:
|
|
300
|
-
timeout = 60
|
|
301
|
-
except Exception:
|
|
302
|
-
timeout = 60
|
|
303
|
-
return timeout
|
|
304
|
-
|
|
305
|
-
# --- Simulation Worker ---
|
|
306
|
-
def simulation_worker(session, alpha_list, mode, json_path, location_path, retry_timeout, batch_size=None):
|
|
307
|
-
locations = {}
|
|
308
|
-
# Initialize sent_count from user starting index (passed via alpha_list attribute if set)
|
|
309
|
-
file_name = os.path.basename(json_path)
|
|
310
|
-
sent_count = getattr(alpha_list, '_start_index', 0)
|
|
311
|
-
while alpha_list:
|
|
312
|
-
# Check session timeout before proceeding
|
|
313
|
-
if check_session_timeout(session) == 0:
|
|
314
|
-
logger.error('Session expired. Stopping simulation worker.')
|
|
315
|
-
break
|
|
316
|
-
session = check_session_and_relogin(session)
|
|
317
|
-
# Prepare batch but do NOT pop yet
|
|
318
|
-
if mode == 'single':
|
|
319
|
-
batch = [alpha_list[0]]
|
|
320
|
-
else:
|
|
321
|
-
size = batch_size if batch_size else min(10, max(2, len(alpha_list)))
|
|
322
|
-
batch = [alpha_list[i] for i in range(min(size, len(alpha_list)))]
|
|
323
|
-
try:
|
|
324
|
-
from ace_lib import start_simulation
|
|
325
|
-
location = None
|
|
326
|
-
while location is None:
|
|
327
|
-
# Check session timeout before each send
|
|
328
|
-
if check_session_timeout(session) == 0:
|
|
329
|
-
logger.error('Session expired. Stopping simulation worker.')
|
|
330
|
-
return
|
|
331
|
-
if mode == 'single':
|
|
332
|
-
response = start_simulation(session, batch[0])
|
|
333
|
-
location = response.headers.get('Location')
|
|
334
|
-
else:
|
|
335
|
-
response = start_simulation(session, batch)
|
|
336
|
-
location = response.headers.get('Location')
|
|
337
|
-
if location is None:
|
|
338
|
-
logger.info(f'Simulation sent, location(s) saved: None')
|
|
339
|
-
logger.info(f'No location received, waiting {retry_timeout} seconds and retrying...')
|
|
340
|
-
time.sleep(retry_timeout)
|
|
341
|
-
# Only pop/remove after location is valid
|
|
342
|
-
if mode == 'single':
|
|
343
|
-
alpha_list.pop(0)
|
|
344
|
-
sent_count += 1
|
|
345
|
-
update_master_log(json_path, sent_count - 1)
|
|
346
|
-
else:
|
|
347
|
-
for _ in range(len(batch)):
|
|
348
|
-
alpha_list.pop(0)
|
|
349
|
-
sent_count += len(batch)
|
|
350
|
-
update_master_log(json_path, sent_count - 1)
|
|
351
|
-
locations[str(time.time())] = location
|
|
352
|
-
with open(location_path, 'w', encoding='utf-8') as f:
|
|
353
|
-
json.dump(locations, f, indent=2)
|
|
354
|
-
# Do NOT overwrite the input JSON file
|
|
355
|
-
logger.info(f'Simulation sent, location(s) saved: {location}')
|
|
356
|
-
except Exception as e:
|
|
357
|
-
logger.error(f'Simulation error: {e}. Retrying in {retry_timeout} seconds.')
|
|
358
|
-
time.sleep(retry_timeout)
|
|
359
|
-
|
|
360
|
-
# --- Result Worker ---
|
|
361
|
-
def result_worker(session, location_path, result_path, poll_interval=30):
|
|
362
|
-
results = {}
|
|
363
|
-
from time import sleep
|
|
364
|
-
while True:
|
|
365
|
-
# Check session timeout before proceeding
|
|
366
|
-
if check_session_timeout(session) == 0:
|
|
367
|
-
logger.error('Session expired. Stopping result worker.')
|
|
368
|
-
break
|
|
369
|
-
session = check_session_and_relogin(session)
|
|
370
|
-
if not os.path.exists(location_path):
|
|
371
|
-
time.sleep(poll_interval)
|
|
372
|
-
continue
|
|
373
|
-
with open(location_path, 'r', encoding='utf-8') as f:
|
|
374
|
-
locations = json.load(f)
|
|
375
|
-
for loc_key, loc_val in locations.items():
|
|
376
|
-
if loc_key in results:
|
|
377
|
-
continue
|
|
378
|
-
if not loc_val or not isinstance(loc_val, str) or not loc_val.startswith('http'):
|
|
379
|
-
logger.error(f'Invalid or missing location for key {loc_key}: {loc_val}')
|
|
380
|
-
continue
|
|
381
|
-
try:
|
|
382
|
-
# Check session timeout before each result fetch
|
|
383
|
-
if check_session_timeout(session) == 0:
|
|
384
|
-
logger.error('Session expired. Stopping result worker.')
|
|
385
|
-
return
|
|
386
|
-
simulation_progress_url = loc_val
|
|
387
|
-
while True:
|
|
388
|
-
simulation_progress = session.get(simulation_progress_url)
|
|
389
|
-
retry_after = simulation_progress.headers.get("Retry-After", 0)
|
|
390
|
-
if float(retry_after) == 0:
|
|
391
|
-
break
|
|
392
|
-
logger.info(f"Sleeping for {retry_after} seconds for location {simulation_progress_url}")
|
|
393
|
-
sleep(float(retry_after))
|
|
394
|
-
sim_json = simulation_progress.json()
|
|
395
|
-
# Multi-simulation: check for children
|
|
396
|
-
if "children" in sim_json and sim_json.get("status") == "COMPLETE":
|
|
397
|
-
child_results = {}
|
|
398
|
-
for child_id in sim_json["children"]:
|
|
399
|
-
child_url = f"https://api.worldquantbrain.com/simulations/{child_id}"
|
|
400
|
-
child_resp = session.get(child_url)
|
|
401
|
-
child_json = child_resp.json()
|
|
402
|
-
alpha_id = child_json.get("alpha")
|
|
403
|
-
if not alpha_id:
|
|
404
|
-
logger.error(f"No alpha_id found for child {child_id}")
|
|
405
|
-
child_results[child_id] = {"error": "No alpha_id found"}
|
|
406
|
-
else:
|
|
407
|
-
alpha = session.get(f"https://api.worldquantbrain.com/alphas/{alpha_id}")
|
|
408
|
-
child_results[child_id] = alpha.json()
|
|
409
|
-
results[loc_key] = {"multi_children": child_results}
|
|
410
|
-
logger.info(f"Multi-simulation results fetched for location {loc_val}")
|
|
411
|
-
else:
|
|
412
|
-
# Single simulation
|
|
413
|
-
alpha_id = sim_json.get("alpha")
|
|
414
|
-
if not alpha_id:
|
|
415
|
-
logger.error(f"No alpha_id found for location {simulation_progress_url}")
|
|
416
|
-
results[loc_key] = {"error": "No alpha_id found"}
|
|
417
|
-
else:
|
|
418
|
-
alpha = session.get(f"https://api.worldquantbrain.com/alphas/{alpha_id}")
|
|
419
|
-
results[loc_key] = alpha.json()
|
|
420
|
-
logger.info(f"Result fetched for location {loc_val}")
|
|
421
|
-
with open(result_path, 'w', encoding='utf-8') as f:
|
|
422
|
-
json.dump(results, f, indent=2)
|
|
423
|
-
except Exception as e:
|
|
424
|
-
logger.error(f'Error fetching result for {loc_val}: {e}')
|
|
425
|
-
time.sleep(poll_interval)
|
|
426
|
-
|
|
427
|
-
# --- Main ---
|
|
428
|
-
def main():
|
|
429
|
-
session = authenticate()
|
|
430
|
-
alpha_list, json_path = get_user_json()
|
|
431
|
-
mode, batch_size = get_simulation_mode()
|
|
432
|
-
retry_timeout = get_retry_timeout()
|
|
433
|
-
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
|
434
|
-
location_path = f'autosim_locations_{timestamp}.json'
|
|
435
|
-
result_path = f'autosim_results_{timestamp}.json'
|
|
436
|
-
# Start workers
|
|
437
|
-
sim_thread = threading.Thread(target=simulation_worker, args=(session, alpha_list, mode, json_path, location_path, retry_timeout, batch_size))
|
|
438
|
-
res_thread = threading.Thread(target=result_worker, args=(session, location_path, result_path))
|
|
439
|
-
sim_thread.start()
|
|
440
|
-
res_thread.start()
|
|
441
|
-
sim_thread.join()
|
|
442
|
-
# Result worker runs until all locations processed
|
|
443
|
-
logger.info('Simulation worker finished. Waiting for results...')
|
|
444
|
-
res_thread.join()
|
|
445
|
-
|
|
446
|
-
if __name__ == '__main__':
|
|
447
|
-
main()
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import os
|
|
3
|
-
from typing import Union
|
|
4
|
-
|
|
5
|
-
import pandas as pd
|
|
6
|
-
from pandas.io.formats.style import Styler
|
|
7
|
-
|
|
8
|
-
brain_api_url = os.environ.get("BRAIN_API_URL", "https://api.worldquantbrain.com")
|
|
9
|
-
brain_url = os.environ.get("BRAIN_URL", "https://platform.worldquantbrain.com")
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def make_clickable_alpha_id(alpha_id: str) -> str:
|
|
13
|
-
"""
|
|
14
|
-
Create a clickable HTML link for an alpha ID.
|
|
15
|
-
|
|
16
|
-
Args:
|
|
17
|
-
alpha_id (str): The ID of the alpha.
|
|
18
|
-
|
|
19
|
-
Returns:
|
|
20
|
-
str: An HTML string containing a clickable link to the alpha's page on the platform.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
url = brain_url + "/alpha/"
|
|
24
|
-
return f'<a href="{url}{alpha_id}">{alpha_id}</a>'
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def prettify_result(
|
|
28
|
-
result: list, detailed_tests_view: bool = False, clickable_alpha_id: bool = False
|
|
29
|
-
) -> Union[pd.DataFrame, Styler]:
|
|
30
|
-
"""
|
|
31
|
-
Combine and format simulation results into a single DataFrame for analysis.
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
result (list): A list of dictionaries containing simulation results.
|
|
35
|
-
detailed_tests_view (bool, optional): If True, include detailed test results. Defaults to False.
|
|
36
|
-
clickable_alpha_id (bool, optional): If True, make alpha IDs clickable. Defaults to False.
|
|
37
|
-
|
|
38
|
-
Returns:
|
|
39
|
-
pandas.DataFrame or pandas.io.formats.style.Styler: A DataFrame containing formatted results,
|
|
40
|
-
optionally with clickable alpha IDs.
|
|
41
|
-
"""
|
|
42
|
-
list_of_is_stats = [result[x]["is_stats"] for x in range(len(result)) if result[x]["is_stats"] is not None]
|
|
43
|
-
is_stats_df = pd.concat(list_of_is_stats).reset_index(drop=True)
|
|
44
|
-
is_stats_df = is_stats_df.sort_values("fitness", ascending=False)
|
|
45
|
-
|
|
46
|
-
expressions = {
|
|
47
|
-
result[x]["alpha_id"]: (
|
|
48
|
-
{
|
|
49
|
-
"selection": result[x]["simulate_data"]["selection"],
|
|
50
|
-
"combo": result[x]["simulate_data"]["combo"],
|
|
51
|
-
}
|
|
52
|
-
if result[x]["simulate_data"]["type"] == "SUPER"
|
|
53
|
-
else result[x]["simulate_data"]["regular"]
|
|
54
|
-
)
|
|
55
|
-
for x in range(len(result))
|
|
56
|
-
if result[x]["is_stats"] is not None
|
|
57
|
-
}
|
|
58
|
-
expression_df = pd.DataFrame(list(expressions.items()), columns=["alpha_id", "expression"])
|
|
59
|
-
|
|
60
|
-
list_of_is_tests = [result[x]["is_tests"] for x in range(len(result)) if result[x]["is_tests"] is not None]
|
|
61
|
-
is_tests_df = pd.concat(list_of_is_tests, sort=True).reset_index(drop=True)
|
|
62
|
-
is_tests_df = is_tests_df[is_tests_df["result"] != "WARNING"]
|
|
63
|
-
if detailed_tests_view:
|
|
64
|
-
cols = ["limit", "result", "value"]
|
|
65
|
-
is_tests_df["details"] = is_tests_df[cols].to_dict(orient="records")
|
|
66
|
-
is_tests_df = is_tests_df.pivot(index="alpha_id", columns="name", values="details").reset_index()
|
|
67
|
-
else:
|
|
68
|
-
is_tests_df = is_tests_df.pivot(index="alpha_id", columns="name", values="result").reset_index()
|
|
69
|
-
|
|
70
|
-
alpha_stats = pd.merge(is_stats_df, expression_df, on="alpha_id")
|
|
71
|
-
alpha_stats = pd.merge(alpha_stats, is_tests_df, on="alpha_id")
|
|
72
|
-
alpha_stats = alpha_stats.drop(columns=alpha_stats.columns[(alpha_stats == "PENDING").any()])
|
|
73
|
-
alpha_stats.columns = alpha_stats.columns.str.replace("(?<=[a-z])(?=[A-Z])", "_", regex=True).str.lower()
|
|
74
|
-
if clickable_alpha_id:
|
|
75
|
-
return alpha_stats.style.format({"alpha_id": lambda x: make_clickable_alpha_id(str(x))})
|
|
76
|
-
return alpha_stats
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def concat_pnl(result: list) -> pd.DataFrame:
|
|
80
|
-
"""
|
|
81
|
-
Combine PnL results from multiple alphas into a single DataFrame.
|
|
82
|
-
|
|
83
|
-
Args:
|
|
84
|
-
result (list): A list of dictionaries containing simulation results with PnL data.
|
|
85
|
-
|
|
86
|
-
Returns:
|
|
87
|
-
pandas.DataFrame: A DataFrame containing combined PnL data for all alphas.
|
|
88
|
-
"""
|
|
89
|
-
list_of_pnls = [result[x]["pnl"] for x in range(len(result)) if result[x]["pnl"] is not None]
|
|
90
|
-
pnls_df = pd.concat(list_of_pnls).reset_index()
|
|
91
|
-
|
|
92
|
-
return pnls_df
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def concat_is_tests(result: list) -> pd.DataFrame:
|
|
96
|
-
"""
|
|
97
|
-
Combine in-sample test results from multiple alphas into a single DataFrame.
|
|
98
|
-
|
|
99
|
-
Args:
|
|
100
|
-
result (list): A list of dictionaries containing simulation results with in-sample test data.
|
|
101
|
-
|
|
102
|
-
Returns:
|
|
103
|
-
pandas.DataFrame: A DataFrame containing combined in-sample test results for all alphas.
|
|
104
|
-
"""
|
|
105
|
-
is_tests_list = [result[x]["is_tests"] for x in range(len(result)) if result[x]["is_tests"] is not None]
|
|
106
|
-
is_tests_df = pd.concat(is_tests_list, sort=True).reset_index(drop=True)
|
|
107
|
-
return is_tests_df
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def save_simulation_result(result: dict) -> None:
|
|
111
|
-
"""
|
|
112
|
-
Save the simulation result to a JSON file in the 'simulation_results' folder.
|
|
113
|
-
|
|
114
|
-
Args:
|
|
115
|
-
result (dict): A dictionary containing the simulation result for an alpha.
|
|
116
|
-
"""
|
|
117
|
-
|
|
118
|
-
alpha_id = result["id"]
|
|
119
|
-
region = result["settings"]["region"]
|
|
120
|
-
folder_path = "simulation_results/"
|
|
121
|
-
file_path = os.path.join(folder_path, f"{alpha_id}_{region}")
|
|
122
|
-
|
|
123
|
-
os.makedirs(folder_path, exist_ok=True)
|
|
124
|
-
|
|
125
|
-
with open(file_path, "w", encoding="utf-8") as file:
|
|
126
|
-
json.dump(result, file)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def save_pnl(pnl_df: pd.DataFrame, alpha_id: str, region: str) -> None:
|
|
130
|
-
"""
|
|
131
|
-
Save the PnL data for an alpha to a CSV file in the 'alphas_pnl' folder.
|
|
132
|
-
|
|
133
|
-
Args:
|
|
134
|
-
pnl_df (pandas.DataFrame): The DataFrame containing PnL data.
|
|
135
|
-
alpha_id (str): The ID of the alpha.
|
|
136
|
-
region (str): The region for which the PnL data was generated.
|
|
137
|
-
"""
|
|
138
|
-
|
|
139
|
-
folder_path = "alphas_pnl/"
|
|
140
|
-
file_path = os.path.join(folder_path, f"{alpha_id}_{region}.csv")
|
|
141
|
-
os.makedirs(folder_path, exist_ok=True)
|
|
142
|
-
|
|
143
|
-
pnl_df.to_csv(file_path)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
def save_yearly_stats(yearly_stats: pd.DataFrame, alpha_id: str, region: str):
|
|
147
|
-
"""
|
|
148
|
-
Save the yearly statistics for an alpha to a CSV file in the 'yearly_stats' folder.
|
|
149
|
-
|
|
150
|
-
Args:
|
|
151
|
-
yearly_stats (pandas.DataFrame): The DataFrame containing yearly statistics.
|
|
152
|
-
alpha_id (str): The ID of the alpha.
|
|
153
|
-
region (str): The region for which the statistics were generated.
|
|
154
|
-
"""
|
|
155
|
-
|
|
156
|
-
folder_path = "yearly_stats/"
|
|
157
|
-
file_path = os.path.join(folder_path, f"{alpha_id}_{region}.csv")
|
|
158
|
-
os.makedirs(folder_path, exist_ok=True)
|
|
159
|
-
|
|
160
|
-
yearly_stats.to_csv(file_path, index=False)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
def expand_dict_columns(data: pd.DataFrame) -> pd.DataFrame:
|
|
164
|
-
"""
|
|
165
|
-
Expand dictionary columns in a DataFrame into separate columns.
|
|
166
|
-
|
|
167
|
-
Args:
|
|
168
|
-
data (pandas.DataFrame): The input DataFrame with dictionary columns.
|
|
169
|
-
|
|
170
|
-
Returns:
|
|
171
|
-
pandas.DataFrame: A new DataFrame with expanded columns.
|
|
172
|
-
"""
|
|
173
|
-
dict_columns = list(filter(lambda x: isinstance(data[x].iloc[0], dict), data.columns))
|
|
174
|
-
new_columns = pd.concat(
|
|
175
|
-
[data[col].apply(pd.Series).rename(columns=lambda x: f"{col}_{x}") for col in dict_columns],
|
|
176
|
-
axis=1,
|
|
177
|
-
)
|
|
178
|
-
|
|
179
|
-
data = pd.concat([data, new_columns], axis=1)
|
|
180
|
-
return data
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# PyPI Mirror Configuration
|
|
2
|
-
# 配置 PyPI 镜像源
|
|
3
|
-
|
|
4
|
-
# Default: Tsinghua University (China)
|
|
5
|
-
# 默认:清华大学镜像源(中国)
|
|
6
|
-
https://pypi.tuna.tsinghua.edu.cn/simple
|
|
7
|
-
|
|
8
|
-
# Alternative mirrors / 其他可选镜像源:
|
|
9
|
-
#
|
|
10
|
-
# Aliyun (阿里云):
|
|
11
|
-
# https://mirrors.aliyun.com/pypi/simple/
|
|
12
|
-
#
|
|
13
|
-
# Douban (豆瓣):
|
|
14
|
-
# https://pypi.douban.com/simple/
|
|
15
|
-
#
|
|
16
|
-
# USTC (中国科学技术大学):
|
|
17
|
-
# https://pypi.mirrors.ustc.edu.cn/simple/
|
|
18
|
-
#
|
|
19
|
-
# Official PyPI (官方源):
|
|
20
|
-
# https://pypi.org/simple
|