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.
Files changed (113) hide show
  1. {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/METADATA +1 -1
  2. cnhkmcp-2.1.3.dist-info/RECORD +6 -0
  3. cnhkmcp-2.1.3.dist-info/top_level.txt +1 -0
  4. cnhkmcp/__init__.py +0 -125
  5. 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
  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/ace.log +0 -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/config.json +0 -6
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. cnhkmcp/untracked/APP/.gitignore +0 -32
  23. cnhkmcp/untracked/APP/MODULAR_STRUCTURE.md +0 -112
  24. cnhkmcp/untracked/APP/README.md +0 -309
  25. cnhkmcp/untracked/APP/Tranformer/Transformer.py +0 -4985
  26. cnhkmcp/untracked/APP/Tranformer/ace.log +0 -0
  27. cnhkmcp/untracked/APP/Tranformer/ace_lib.py +0 -1510
  28. cnhkmcp/untracked/APP/Tranformer/helpful_functions.py +0 -180
  29. cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates.json +0 -2421
  30. cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates_/321/207/320/264/342/225/221/321/204/342/225/233/320/233.json +0 -654
  31. cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_error.json +0 -1034
  32. cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_success.json +0 -444
  33. 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
  34. cnhkmcp/untracked/APP/Tranformer/parsetab.py +0 -60
  35. cnhkmcp/untracked/APP/Tranformer/template_summary.txt +0 -3182
  36. cnhkmcp/untracked/APP/Tranformer/transformer_config.json +0 -7
  37. cnhkmcp/untracked/APP/Tranformer/validator.py +0 -889
  38. cnhkmcp/untracked/APP/ace.log +0 -69
  39. cnhkmcp/untracked/APP/ace_lib.py +0 -1510
  40. cnhkmcp/untracked/APP/blueprints/__init__.py +0 -6
  41. cnhkmcp/untracked/APP/blueprints/feature_engineering.py +0 -347
  42. cnhkmcp/untracked/APP/blueprints/idea_house.py +0 -221
  43. cnhkmcp/untracked/APP/blueprints/inspiration_house.py +0 -432
  44. cnhkmcp/untracked/APP/blueprints/paper_analysis.py +0 -570
  45. cnhkmcp/untracked/APP/custom_templates/templates.json +0 -1257
  46. cnhkmcp/untracked/APP/give_me_idea/BRAIN_Alpha_Template_Expert_SystemPrompt.md +0 -400
  47. cnhkmcp/untracked/APP/give_me_idea/ace_lib.py +0 -1510
  48. cnhkmcp/untracked/APP/give_me_idea/alpha_data_specific_template_master.py +0 -252
  49. cnhkmcp/untracked/APP/give_me_idea/fetch_all_datasets.py +0 -157
  50. cnhkmcp/untracked/APP/give_me_idea/fetch_all_operators.py +0 -99
  51. cnhkmcp/untracked/APP/give_me_idea/helpful_functions.py +0 -180
  52. cnhkmcp/untracked/APP/give_me_idea/what_is_Alpha_template.md +0 -11
  53. cnhkmcp/untracked/APP/helpful_functions.py +0 -180
  54. cnhkmcp/untracked/APP/hkSimulator/ace_lib.py +0 -1497
  55. cnhkmcp/untracked/APP/hkSimulator/autosimulator.py +0 -447
  56. cnhkmcp/untracked/APP/hkSimulator/helpful_functions.py +0 -180
  57. cnhkmcp/untracked/APP/mirror_config.txt +0 -20
  58. cnhkmcp/untracked/APP/operaters.csv +0 -129
  59. cnhkmcp/untracked/APP/requirements.txt +0 -53
  60. cnhkmcp/untracked/APP/run_app.bat +0 -28
  61. cnhkmcp/untracked/APP/run_app.sh +0 -34
  62. cnhkmcp/untracked/APP/setup_tsinghua.bat +0 -39
  63. cnhkmcp/untracked/APP/setup_tsinghua.sh +0 -43
  64. cnhkmcp/untracked/APP/simulator/alpha_submitter.py +0 -404
  65. cnhkmcp/untracked/APP/simulator/simulator_wqb.py +0 -618
  66. cnhkmcp/untracked/APP/ssrn-3332513.pdf +6 -109201
  67. cnhkmcp/untracked/APP/static/brain.js +0 -589
  68. cnhkmcp/untracked/APP/static/decoder.js +0 -1540
  69. cnhkmcp/untracked/APP/static/feature_engineering.js +0 -1729
  70. cnhkmcp/untracked/APP/static/idea_house.js +0 -937
  71. cnhkmcp/untracked/APP/static/inspiration.js +0 -465
  72. cnhkmcp/untracked/APP/static/inspiration_house.js +0 -868
  73. cnhkmcp/untracked/APP/static/paper_analysis.js +0 -390
  74. cnhkmcp/untracked/APP/static/script.js +0 -3082
  75. cnhkmcp/untracked/APP/static/simulator.js +0 -597
  76. cnhkmcp/untracked/APP/static/styles.css +0 -3127
  77. cnhkmcp/untracked/APP/static/usage_widget.js +0 -508
  78. cnhkmcp/untracked/APP/templates/alpha_inspector.html +0 -511
  79. cnhkmcp/untracked/APP/templates/feature_engineering.html +0 -960
  80. cnhkmcp/untracked/APP/templates/idea_house.html +0 -564
  81. cnhkmcp/untracked/APP/templates/index.html +0 -932
  82. cnhkmcp/untracked/APP/templates/inspiration_house.html +0 -861
  83. cnhkmcp/untracked/APP/templates/paper_analysis.html +0 -91
  84. cnhkmcp/untracked/APP/templates/simulator.html +0 -343
  85. cnhkmcp/untracked/APP/templates/transformer_web.html +0 -580
  86. cnhkmcp/untracked/APP/usage.md +0 -351
  87. 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
  88. 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
  89. 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
  90. 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
  91. cnhkmcp/untracked/arXiv_API_Tool_Manual.md +0 -490
  92. cnhkmcp/untracked/arxiv_api.py +0 -229
  93. cnhkmcp/untracked/forum_functions.py +0 -998
  94. 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
  95. 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
  96. 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
  97. 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
  98. 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
  99. cnhkmcp/untracked/platform_functions.py +0 -2886
  100. cnhkmcp/untracked/sample_mcp_config.json +0 -11
  101. cnhkmcp/untracked/user_config.json +0 -31
  102. 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
  103. 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
  104. 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
  105. 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
  106. 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
  107. 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
  108. 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
  109. cnhkmcp-2.1.2.dist-info/RECORD +0 -111
  110. cnhkmcp-2.1.2.dist-info/top_level.txt +0 -1
  111. {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/WHEEL +0 -0
  112. {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/entry_points.txt +0 -0
  113. {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