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,252 +0,0 @@
|
|
|
1
|
-
import ace_lib
|
|
2
|
-
import pandas as pd
|
|
3
|
-
import json
|
|
4
|
-
import openai
|
|
5
|
-
import os
|
|
6
|
-
import sys
|
|
7
|
-
import time
|
|
8
|
-
import random
|
|
9
|
-
|
|
10
|
-
# Default Moonshot Configuration
|
|
11
|
-
DEFAULT_MOONSHOT_BASE_URL = "https://api.moonshot.cn/v1"
|
|
12
|
-
DEFAULT_MOONSHOT_MODEL = "kimi-k2-turbo-preview"
|
|
13
|
-
|
|
14
|
-
def get_llm_client(api_key, base_url):
|
|
15
|
-
return openai.OpenAI(
|
|
16
|
-
api_key=api_key,
|
|
17
|
-
base_url=base_url,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
def test_llm_connection(api_key, base_url, model):
|
|
21
|
-
print("\nTesting LLM connection...")
|
|
22
|
-
client = get_llm_client(api_key, base_url)
|
|
23
|
-
try:
|
|
24
|
-
client.chat.completions.create(
|
|
25
|
-
model=model,
|
|
26
|
-
messages=[{"role": "user", "content": "Hello"}],
|
|
27
|
-
max_tokens=5
|
|
28
|
-
)
|
|
29
|
-
print("LLM connection successful.")
|
|
30
|
-
return True
|
|
31
|
-
except Exception as e:
|
|
32
|
-
print(f"LLM connection failed: {e}")
|
|
33
|
-
return False
|
|
34
|
-
|
|
35
|
-
def call_llm_with_retry(client, model, system_prompt, operators_df, datafields_df, dataset_id, max_retries=5):
|
|
36
|
-
|
|
37
|
-
n_ops = len(operators_df)
|
|
38
|
-
n_fields = len(datafields_df)
|
|
39
|
-
|
|
40
|
-
for attempt in range(max_retries + 1):
|
|
41
|
-
print(f"\nAttempt {attempt + 1}/{max_retries + 1} - Preparing prompt with {n_ops} operators and {n_fields} datafields...")
|
|
42
|
-
|
|
43
|
-
# Sample rows if needed, otherwise take head
|
|
44
|
-
# Using head for stability, but could be random sample
|
|
45
|
-
ops_subset = operators_df.head(n_ops)
|
|
46
|
-
fields_subset = datafields_df.head(n_fields)
|
|
47
|
-
|
|
48
|
-
operators_info = ops_subset[['name', 'category', 'description', 'extra_side_note']].to_string()
|
|
49
|
-
datafields_info = fields_subset[['id', 'description', 'subcategory']].to_string()
|
|
50
|
-
|
|
51
|
-
user_prompt = f"""
|
|
52
|
-
Here is the information about available operators (first {n_ops} rows):
|
|
53
|
-
{operators_info}
|
|
54
|
-
|
|
55
|
-
Here is the information about the dataset '{dataset_id}' (first {n_fields} rows):
|
|
56
|
-
{datafields_info}
|
|
57
|
-
|
|
58
|
-
Please come up with several Alpha templates based on this information.
|
|
59
|
-
Specify the AI answer in Chinese.
|
|
60
|
-
"""
|
|
61
|
-
|
|
62
|
-
try:
|
|
63
|
-
print("Sending request to LLM...")
|
|
64
|
-
completion = client.chat.completions.create(
|
|
65
|
-
model=model,
|
|
66
|
-
messages=[
|
|
67
|
-
{"role": "system", "content": system_prompt},
|
|
68
|
-
{"role": "user", "content": user_prompt}
|
|
69
|
-
],
|
|
70
|
-
temperature=0.3,
|
|
71
|
-
)
|
|
72
|
-
return completion.choices[0].message.content
|
|
73
|
-
|
|
74
|
-
except openai.BadRequestError as e:
|
|
75
|
-
error_msg = str(e)
|
|
76
|
-
print(f"LLM Bad Request Error: {error_msg}")
|
|
77
|
-
|
|
78
|
-
# Check for token limit error
|
|
79
|
-
if "token limit" in error_msg or "context_length_exceeded" in error_msg or "400" in error_msg:
|
|
80
|
-
print("Token limit exceeded. Reducing context size...")
|
|
81
|
-
n_ops = max(1, n_ops // 2)
|
|
82
|
-
n_fields = max(1, n_fields // 2)
|
|
83
|
-
if n_ops == 1 and n_fields == 1:
|
|
84
|
-
print("Cannot reduce context further.")
|
|
85
|
-
return f"Failed after retries: {e}"
|
|
86
|
-
else:
|
|
87
|
-
return f"LLM Error (not token related): {e}"
|
|
88
|
-
|
|
89
|
-
except Exception as e:
|
|
90
|
-
return f"General Error calling LLM: {e}"
|
|
91
|
-
|
|
92
|
-
return "Max retries exceeded."
|
|
93
|
-
|
|
94
|
-
def main():
|
|
95
|
-
print("=== BRAIN Alpha Generator Full Version ===\n")
|
|
96
|
-
|
|
97
|
-
# 1. Interactive Login
|
|
98
|
-
print("--- Step 1: Login to BRAIN ---")
|
|
99
|
-
email = input("Enter BRAIN Email: ").strip()
|
|
100
|
-
while not email:
|
|
101
|
-
email = input("Email is required. Enter BRAIN Email: ").strip()
|
|
102
|
-
|
|
103
|
-
import getpass
|
|
104
|
-
password = getpass.getpass("Enter BRAIN Password: ").strip()
|
|
105
|
-
while not password:
|
|
106
|
-
password = getpass.getpass("Password is required. Enter BRAIN Password: ").strip()
|
|
107
|
-
|
|
108
|
-
# Monkeypatch ace_lib.get_credentials to use provided inputs
|
|
109
|
-
ace_lib.get_credentials = lambda: (email, password)
|
|
110
|
-
|
|
111
|
-
print("Logging in...")
|
|
112
|
-
try:
|
|
113
|
-
s = ace_lib.start_session()
|
|
114
|
-
print("Login successful.")
|
|
115
|
-
except Exception as e:
|
|
116
|
-
print(f"Login failed: {e}")
|
|
117
|
-
return
|
|
118
|
-
|
|
119
|
-
# 2. LLM Configuration
|
|
120
|
-
print("\n--- Step 2: LLM Configuration ---")
|
|
121
|
-
base_url = input(f"Enter LLM Base URL (default: {DEFAULT_MOONSHOT_BASE_URL}): ").strip()
|
|
122
|
-
if not base_url:
|
|
123
|
-
base_url = DEFAULT_MOONSHOT_BASE_URL
|
|
124
|
-
|
|
125
|
-
api_key = input("Enter LLM API Key (required): ").strip()
|
|
126
|
-
while not api_key:
|
|
127
|
-
print("API Key is required.")
|
|
128
|
-
api_key = input("Enter LLM API Key: ").strip()
|
|
129
|
-
|
|
130
|
-
model_name = input(f"Enter LLM Model Name (default: {DEFAULT_MOONSHOT_MODEL}): ").strip()
|
|
131
|
-
if not model_name:
|
|
132
|
-
model_name = DEFAULT_MOONSHOT_MODEL
|
|
133
|
-
|
|
134
|
-
if not test_llm_connection(api_key, base_url, model_name):
|
|
135
|
-
print("Aborting due to LLM connection failure.")
|
|
136
|
-
return
|
|
137
|
-
|
|
138
|
-
llm_client = get_llm_client(api_key, base_url)
|
|
139
|
-
|
|
140
|
-
# 3. Load Operators
|
|
141
|
-
print("\n--- Step 3: Load Operators ---")
|
|
142
|
-
print("Getting operators...")
|
|
143
|
-
try:
|
|
144
|
-
operators_df = ace_lib.get_operators(s)
|
|
145
|
-
operators_df = operators_df[operators_df['scope'] == 'REGULAR']
|
|
146
|
-
print(f"Retrieved {len(operators_df)} operators (REGULAR only).")
|
|
147
|
-
|
|
148
|
-
print("Fetching documentation for operators...")
|
|
149
|
-
operators_df = operators_df.copy()
|
|
150
|
-
|
|
151
|
-
def fetch_doc_content(doc_path):
|
|
152
|
-
if pd.isna(doc_path) or not doc_path:
|
|
153
|
-
return None
|
|
154
|
-
url = ace_lib.brain_api_url + doc_path
|
|
155
|
-
try:
|
|
156
|
-
r = s.get(url)
|
|
157
|
-
if r.status_code == 200:
|
|
158
|
-
return json.dumps(r.json())
|
|
159
|
-
return None
|
|
160
|
-
except Exception:
|
|
161
|
-
return None
|
|
162
|
-
|
|
163
|
-
operators_df['extra_side_note'] = operators_df['documentation'].apply(fetch_doc_content)
|
|
164
|
-
operators_df.drop(columns=['documentation', 'level'], inplace=True)
|
|
165
|
-
print("Operators loaded and processed.")
|
|
166
|
-
|
|
167
|
-
except Exception as e:
|
|
168
|
-
print(f"Failed to get operators: {e}")
|
|
169
|
-
return
|
|
170
|
-
|
|
171
|
-
# 4. Dataset Selection
|
|
172
|
-
print("\n--- Step 4: Select Dataset ---")
|
|
173
|
-
region = input("Enter Region (default: USA): ").strip() or "USA"
|
|
174
|
-
delay = input("Enter Delay (default: 1): ").strip() or "1"
|
|
175
|
-
universe = input("Enter Universe (default: TOP3000): ").strip() or "TOP3000"
|
|
176
|
-
|
|
177
|
-
try:
|
|
178
|
-
delay = int(delay)
|
|
179
|
-
except ValueError:
|
|
180
|
-
print("Invalid delay, using default 1")
|
|
181
|
-
delay = 1
|
|
182
|
-
|
|
183
|
-
print(f"Fetching datasets for Region={region}, Delay={delay}, Universe={universe}...")
|
|
184
|
-
try:
|
|
185
|
-
datasets_df = ace_lib.get_datasets(
|
|
186
|
-
s,
|
|
187
|
-
region=region,
|
|
188
|
-
delay=delay,
|
|
189
|
-
universe=universe
|
|
190
|
-
)
|
|
191
|
-
print(f"Retrieved {len(datasets_df)} datasets.")
|
|
192
|
-
# print(datasets_df[['id', 'name', 'category', 'subcategory']].head(10))
|
|
193
|
-
|
|
194
|
-
# Print all datasets for user selection
|
|
195
|
-
pd.set_option('display.max_rows', None)
|
|
196
|
-
print(datasets_df[['id', 'name', 'category', 'subcategory']])
|
|
197
|
-
except Exception as e:
|
|
198
|
-
print(f"Failed to get datasets: {e}")
|
|
199
|
-
return
|
|
200
|
-
|
|
201
|
-
# 5. Dataset Detail
|
|
202
|
-
print("\n--- Step 5: Get Dataset Details ---")
|
|
203
|
-
dataset_id = input("Enter Dataset ID to analyze (e.g., analyst10): ").strip()
|
|
204
|
-
while not dataset_id:
|
|
205
|
-
dataset_id = input("Dataset ID is required: ").strip()
|
|
206
|
-
|
|
207
|
-
print(f"Getting datafields for dataset: {dataset_id}...")
|
|
208
|
-
try:
|
|
209
|
-
datafields_df = ace_lib.get_datafields(
|
|
210
|
-
s,
|
|
211
|
-
region=region,
|
|
212
|
-
delay=delay,
|
|
213
|
-
universe=universe,
|
|
214
|
-
data_type="ALL",
|
|
215
|
-
dataset_id=dataset_id
|
|
216
|
-
)
|
|
217
|
-
print(f"Retrieved {len(datafields_df)} datafields.")
|
|
218
|
-
except Exception as e:
|
|
219
|
-
print(f"Failed to get datafields: {e}")
|
|
220
|
-
return
|
|
221
|
-
|
|
222
|
-
# 6. Generate Alpha Templates
|
|
223
|
-
print("\n--- Step 6: Generate Alpha Templates ---")
|
|
224
|
-
|
|
225
|
-
# Load System Prompt
|
|
226
|
-
# Use relative path based on the script location
|
|
227
|
-
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
228
|
-
system_prompt_path = os.path.join(script_dir, "what_is_Alpha_template.md")
|
|
229
|
-
|
|
230
|
-
try:
|
|
231
|
-
with open(system_prompt_path, "r", encoding="utf-8") as f:
|
|
232
|
-
system_prompt = f.read()
|
|
233
|
-
print(f"System prompt loaded from {system_prompt_path}")
|
|
234
|
-
except Exception as e:
|
|
235
|
-
print(f"System prompt file not found at {system_prompt_path}, using default. Error: {e}")
|
|
236
|
-
system_prompt = "You are a helpful assistant for generating Alpha templates."
|
|
237
|
-
|
|
238
|
-
response = call_llm_with_retry(
|
|
239
|
-
llm_client,
|
|
240
|
-
model_name,
|
|
241
|
-
system_prompt,
|
|
242
|
-
operators_df,
|
|
243
|
-
datafields_df,
|
|
244
|
-
dataset_id
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
print("\n=== LLM Response ===")
|
|
248
|
-
print(response)
|
|
249
|
-
print("====================")
|
|
250
|
-
|
|
251
|
-
if __name__ == "__main__":
|
|
252
|
-
main()
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import getpass
|
|
2
|
-
import json
|
|
3
|
-
import os
|
|
4
|
-
import sys
|
|
5
|
-
from typing import List
|
|
6
|
-
|
|
7
|
-
import pandas as pd
|
|
8
|
-
|
|
9
|
-
# Ensure we can import ace_lib from the project root
|
|
10
|
-
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
11
|
-
ROOT_DIR = os.path.dirname(SCRIPT_DIR)
|
|
12
|
-
if ROOT_DIR not in sys.path:
|
|
13
|
-
sys.path.append(ROOT_DIR)
|
|
14
|
-
|
|
15
|
-
import ace_lib # noqa: E402
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def prompt_credentials() -> tuple[str, str]:
|
|
19
|
-
"""Prompt user for platform credentials."""
|
|
20
|
-
email = input("Enter BRAIN Email: ").strip()
|
|
21
|
-
while not email:
|
|
22
|
-
email = input("Email is required. Enter BRAIN Email: ").strip()
|
|
23
|
-
|
|
24
|
-
password = getpass.getpass("Enter BRAIN Password: ").strip()
|
|
25
|
-
while not password:
|
|
26
|
-
password = getpass.getpass("Password is required. Enter BRAIN Password: ").strip()
|
|
27
|
-
|
|
28
|
-
return email, password
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def fetch_all_combinations(session: ace_lib.SingleSession) -> pd.DataFrame:
|
|
32
|
-
"""Return all valid instrument/region/delay/universe combos from platform settings."""
|
|
33
|
-
options_df = ace_lib.get_instrument_type_region_delay(session)
|
|
34
|
-
if options_df is None or options_df.empty:
|
|
35
|
-
raise RuntimeError("No simulation options fetched; cannot enumerate datasets.")
|
|
36
|
-
return options_df
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def fetch_datasets_for_combo(
|
|
40
|
-
session: ace_lib.SingleSession,
|
|
41
|
-
instrument_type: str,
|
|
42
|
-
region: str,
|
|
43
|
-
delay: int,
|
|
44
|
-
universe: str,
|
|
45
|
-
) -> pd.DataFrame:
|
|
46
|
-
"""Fetch datasets for one combination (theme ALL to include both theme true/false)."""
|
|
47
|
-
df = ace_lib.get_datasets(
|
|
48
|
-
session,
|
|
49
|
-
instrument_type=instrument_type,
|
|
50
|
-
region=region,
|
|
51
|
-
delay=delay,
|
|
52
|
-
universe=universe,
|
|
53
|
-
theme="ALL",
|
|
54
|
-
)
|
|
55
|
-
if df is None:
|
|
56
|
-
return pd.DataFrame()
|
|
57
|
-
|
|
58
|
-
df = df.copy()
|
|
59
|
-
df["param_instrument_type"] = instrument_type
|
|
60
|
-
df["param_region"] = region
|
|
61
|
-
df["param_delay"] = delay
|
|
62
|
-
df["param_universe"] = universe
|
|
63
|
-
df["combo_key"] = df.apply(
|
|
64
|
-
lambda row: f"{instrument_type}-{region}-D{delay}-{universe}",
|
|
65
|
-
axis=1,
|
|
66
|
-
)
|
|
67
|
-
return df
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def merge_and_deduplicate(datasets: List[pd.DataFrame]) -> pd.DataFrame:
|
|
71
|
-
"""Merge fetched datasets and deduplicate by dataset id, keeping all combo metadata."""
|
|
72
|
-
combined = pd.concat([df for df in datasets if not df.empty], ignore_index=True)
|
|
73
|
-
if combined.empty:
|
|
74
|
-
return combined
|
|
75
|
-
|
|
76
|
-
# Aggregate availability combos per dataset id
|
|
77
|
-
availability = (
|
|
78
|
-
combined.groupby("id")["combo_key"]
|
|
79
|
-
.agg(lambda x: " | ".join(sorted(set(x))))
|
|
80
|
-
.rename("available_in")
|
|
81
|
-
.reset_index()
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
# Drop duplicate rows by dataset id, keep first occurrence of other columns
|
|
85
|
-
unique_df = combined.drop_duplicates(subset=["id"]).copy()
|
|
86
|
-
unique_df = unique_df.merge(availability, on="id", how="left")
|
|
87
|
-
|
|
88
|
-
# Sort for readability
|
|
89
|
-
sort_cols = [col for col in ["category", "subcategory", "id"] if col in unique_df.columns]
|
|
90
|
-
if sort_cols:
|
|
91
|
-
# Ensure sort keys are hashable/strings to avoid unhashable dict errors
|
|
92
|
-
for col in sort_cols:
|
|
93
|
-
unique_df[col] = unique_df[col].apply(
|
|
94
|
-
lambda v: v
|
|
95
|
-
if pd.isna(v) or isinstance(v, (int, float, str, bool))
|
|
96
|
-
else json.dumps(v, ensure_ascii=False, sort_keys=True)
|
|
97
|
-
)
|
|
98
|
-
unique_df = unique_df.sort_values(sort_cols).reset_index(drop=True)
|
|
99
|
-
|
|
100
|
-
return unique_df
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def main():
|
|
104
|
-
print("=== Fetch All BRAIN Datasets (all regions/universes/delays) ===")
|
|
105
|
-
|
|
106
|
-
email, password = prompt_credentials()
|
|
107
|
-
|
|
108
|
-
# Monkey-patch ace_lib credential retrieval so start_session uses provided credentials
|
|
109
|
-
ace_lib.get_credentials = lambda: (email, password)
|
|
110
|
-
|
|
111
|
-
print("Logging in...")
|
|
112
|
-
try:
|
|
113
|
-
session = ace_lib.start_session()
|
|
114
|
-
print("Login successful.")
|
|
115
|
-
except Exception as exc:
|
|
116
|
-
print(f"Login failed: {exc}")
|
|
117
|
-
return
|
|
118
|
-
|
|
119
|
-
print("Fetching valid instrument/region/delay/universe combinations from platform settings...")
|
|
120
|
-
try:
|
|
121
|
-
options_df = fetch_all_combinations(session)
|
|
122
|
-
except Exception as exc:
|
|
123
|
-
print(f"Failed to fetch simulation options: {exc}")
|
|
124
|
-
return
|
|
125
|
-
|
|
126
|
-
all_datasets: List[pd.DataFrame] = []
|
|
127
|
-
total_combos = 0
|
|
128
|
-
|
|
129
|
-
for _, row in options_df.iterrows():
|
|
130
|
-
instrument_type = row.get("InstrumentType")
|
|
131
|
-
region = row.get("Region")
|
|
132
|
-
delay = row.get("Delay")
|
|
133
|
-
universes = row.get("Universe") or []
|
|
134
|
-
|
|
135
|
-
for universe in universes:
|
|
136
|
-
total_combos += 1
|
|
137
|
-
print(f"[{total_combos}] Fetching datasets for {instrument_type} / {region} / D{delay} / {universe}...")
|
|
138
|
-
try:
|
|
139
|
-
df = fetch_datasets_for_combo(session, instrument_type, region, delay, universe)
|
|
140
|
-
print(f" -> Retrieved {len(df)} rows")
|
|
141
|
-
all_datasets.append(df)
|
|
142
|
-
except Exception as exc:
|
|
143
|
-
print(f" -> Failed for {instrument_type}-{region}-D{delay}-{universe}: {exc}")
|
|
144
|
-
|
|
145
|
-
result_df = merge_and_deduplicate(all_datasets)
|
|
146
|
-
|
|
147
|
-
if result_df.empty:
|
|
148
|
-
print("No datasets fetched; nothing to save.")
|
|
149
|
-
return
|
|
150
|
-
|
|
151
|
-
output_path = os.path.join(SCRIPT_DIR, "all_datasets_full.csv")
|
|
152
|
-
result_df.to_csv(output_path, index=False)
|
|
153
|
-
print(f"Saved {len(result_df)} unique datasets to {output_path}")
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if __name__ == "__main__":
|
|
157
|
-
main()
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import getpass
|
|
2
|
-
import os
|
|
3
|
-
import sys
|
|
4
|
-
from typing import List
|
|
5
|
-
|
|
6
|
-
import pandas as pd
|
|
7
|
-
|
|
8
|
-
# Make ace_lib importable
|
|
9
|
-
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
10
|
-
ROOT_DIR = os.path.dirname(SCRIPT_DIR)
|
|
11
|
-
if ROOT_DIR not in sys.path:
|
|
12
|
-
sys.path.append(ROOT_DIR)
|
|
13
|
-
|
|
14
|
-
import ace_lib # noqa: E402
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def prompt_credentials() -> tuple[str, str]:
|
|
18
|
-
email = input("Enter BRAIN Email: ").strip()
|
|
19
|
-
while not email:
|
|
20
|
-
email = input("Email is required. Enter BRAIN Email: ").strip()
|
|
21
|
-
|
|
22
|
-
password = getpass.getpass("Enter BRAIN Password: ").strip()
|
|
23
|
-
while not password:
|
|
24
|
-
password = getpass.getpass("Password is required. Enter BRAIN Password: ").strip()
|
|
25
|
-
|
|
26
|
-
return email, password
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def fetch_operators(session: ace_lib.SingleSession) -> pd.DataFrame:
|
|
30
|
-
df = ace_lib.get_operators(session)
|
|
31
|
-
if df is None or df.empty:
|
|
32
|
-
return pd.DataFrame()
|
|
33
|
-
|
|
34
|
-
df = df.copy()
|
|
35
|
-
|
|
36
|
-
# Choose an identifier column robustly
|
|
37
|
-
id_col = "id" if "id" in df.columns else None
|
|
38
|
-
if id_col is None:
|
|
39
|
-
if "name" in df.columns:
|
|
40
|
-
id_col = "name"
|
|
41
|
-
else:
|
|
42
|
-
id_col = "_row_id"
|
|
43
|
-
df[id_col] = df.index
|
|
44
|
-
|
|
45
|
-
# Re-aggregate scopes so each operator id is unique
|
|
46
|
-
if "scope" in df.columns:
|
|
47
|
-
scope_map = (
|
|
48
|
-
df.groupby(id_col)["scope"]
|
|
49
|
-
.agg(lambda x: sorted(set([item for item in x if pd.notna(item)])))
|
|
50
|
-
.rename("scopes")
|
|
51
|
-
.reset_index()
|
|
52
|
-
)
|
|
53
|
-
else:
|
|
54
|
-
scope_map = pd.DataFrame({id_col: df[id_col].unique(), "scopes": [[] for _ in range(df[id_col].nunique())]})
|
|
55
|
-
|
|
56
|
-
unique_df = df.drop(columns=["scope"], errors="ignore").drop_duplicates(subset=[id_col]).merge(
|
|
57
|
-
scope_map, on=id_col, how="left"
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
# Sort for readability
|
|
61
|
-
sort_cols: List[str] = [col for col in ["category", "subcategory", "name", id_col] if col in unique_df.columns]
|
|
62
|
-
if sort_cols:
|
|
63
|
-
unique_df = unique_df.sort_values(sort_cols).reset_index(drop=True)
|
|
64
|
-
|
|
65
|
-
return unique_df
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def main():
|
|
69
|
-
print("=== Fetch All BRAIN Operators ===")
|
|
70
|
-
|
|
71
|
-
email, password = prompt_credentials()
|
|
72
|
-
ace_lib.get_credentials = lambda: (email, password)
|
|
73
|
-
|
|
74
|
-
print("Logging in...")
|
|
75
|
-
try:
|
|
76
|
-
session = ace_lib.start_session()
|
|
77
|
-
print("Login successful.")
|
|
78
|
-
except Exception as exc:
|
|
79
|
-
print(f"Login failed: {exc}")
|
|
80
|
-
return
|
|
81
|
-
|
|
82
|
-
print("Fetching operators...")
|
|
83
|
-
try:
|
|
84
|
-
operators_df = fetch_operators(session)
|
|
85
|
-
except Exception as exc:
|
|
86
|
-
print(f"Failed to fetch operators: {exc}")
|
|
87
|
-
return
|
|
88
|
-
|
|
89
|
-
if operators_df.empty:
|
|
90
|
-
print("No operators returned; nothing to save.")
|
|
91
|
-
return
|
|
92
|
-
|
|
93
|
-
output_path = os.path.join(SCRIPT_DIR, "all_operators.csv")
|
|
94
|
-
operators_df.to_csv(output_path, index=False)
|
|
95
|
-
print(f"Saved {len(operators_df)} operators to {output_path}")
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if __name__ == "__main__":
|
|
99
|
-
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
|