cnhkmcp 2.1.3__py3-none-any.whl → 2.1.5__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/__init__.py +126 -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/README.md +38 -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/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 +6 -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/get_knowledgeBase_tool/ace_lib.py +1514 -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/get_knowledgeBase_tool/fetch_all_datasets.py +157 -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/get_knowledgeBase_tool/fetch_all_documentation.py +132 -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/get_knowledgeBase_tool/fetch_all_operators.py +99 -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/get_knowledgeBase_tool/helpful_functions.py +180 -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.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/001_10_Steps_to_Start_on_BRAIN_documentation.json +14 -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/001_Intermediate_Pack_-_Improve_your_Alpha_2_2_documentation.json +174 -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/001_Intermediate_Pack_-_Understand_Results_1_2_documentation.json +167 -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/001_Introduction_to_Alphas_documentation.json +145 -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/001_Introduction_to_BRAIN_Expression_Language_documentation.json +107 -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/001_WorldQuant_Challenge_documentation.json +56 -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/001__Read_this_First_-_Starter_Pack_documentation.json +404 -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/002_How_to_choose_the_Simulation_Settings_documentation.json +268 -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/002_Simulate_your_first_Alpha_documentation.json +88 -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/002__Alpha_Examples_for_Beginners_documentation.json +254 -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/002__Alpha_Examples_for_Bronze_Users_documentation.json +114 -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/002__Alpha_Examples_for_Silver_Users_documentation.json +79 -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/002__How_BRAIN_works_documentation.json +184 -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/003_Clear_these_tests_before_submitting_an_Alpha_documentation.json +388 -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/003_Parameters_in_the_Simulation_results_documentation.json +243 -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/004_Group_Data_Fields_documentation.json +69 -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/004_How_to_use_the_Data_Explorer_documentation.json +142 -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/004_Model77_dataset_documentation.json +14 -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/004_Sentiment1_dataset_documentation.json +14 -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/004_Understanding_Data_in_BRAIN_Key_Concepts_and_Tips_documentation.json +182 -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/004_Vector_Data_Fields_documentation.json +30 -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/005_Crowding_Risk-Neutralized_Alphas_documentation.json +64 -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/005_D0_documentation.json +66 -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/005_Double_Neutralization_documentation.json +53 -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/005_Fast_D1_Documentation_documentation.json +304 -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/005_Investability_Constrained_Metrics_documentation.json +129 -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/005_Must-read_posts_How_to_improve_your_Alphas_documentation.json +14 -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/005_Neutralization_documentation.json +29 -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/005_RAM_Risk-Neutralized_Alphas_documentation.json +64 -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/005_Risk_Neutralization_Default_setting_documentation.json +75 -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/005_Risk_Neutralized_Alphas_documentation.json +171 -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/005_Statistical_Risk-Neutralized_Alphas_documentation.json +51 -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/006_EUR_TOP2500_Universe_documentation.json +35 -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/006_GLB_TOPDIV3000_Universe_documentation.json +48 -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/006_Getting_Started_China_Research_for_Consultants_Gold_documentation.json +142 -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/006_Getting_started_on_Illiquid_Universes_Gold_documentation.json +46 -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/006_Getting_started_with_USA_TOPSP500_universe_Gold_documentation.json +62 -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/006_Global_Alphas_Gold_documentation.json +66 -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/006_India_Alphas_documentation.json +35 -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/007_Consultant_Dos_and_Don_ts_documentation.json +35 -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/007_Consultant_Features_documentation.json +239 -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/007_Consultant_Simulation_Features_documentation.json +149 -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/007_Consultant_Submission_Tests_documentation.json +363 -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/007_Finding_Consultant_Alphas_documentation.json +333 -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/007_Power_Pool_Alphas_documentation.json +14 -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/007_Research_Advisory_Program_documentation.json +35 -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/007_Starting_Guide_for_Research_Consultants_documentation.json +14 -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/007_Visualization_Tool_documentation.json +99 -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/007_Your_Advisor_-_Kunqi_Jiang_documentation.json +53 -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/007__Brain_Genius_documentation.json +288 -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/007__Single_Dataset_Alphas_documentation.json +41 -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/008_Advisory_Theme_Calendar_documentation.json +14 -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/008_Multiplier_Rules_documentation.json +14 -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/008_Overview_of_Themes_documentation.json +14 -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/008_Theme_Calendar_documentation.json +14 -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/009_Combo_Expression_documentation.json +272 -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/009_Global_SuperAlphas_documentation.json +14 -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/009_Helpful_Tips_documentation.json +58 -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/009_Selection_Expression_documentation.json +1546 -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/009_SuperAlpha_Operators_documentation.json +890 -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/009_SuperAlpha_Results_documentation.json +83 -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/009_What_is_a_SuperAlpha_documentation.json +261 -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/010_BRAIN_API_documentation.json +515 -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/010_Documentation_for_ACE_API_Library_Gold_documentation.json +27 -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/010__Understanding_simulation_limits_documentation.json +210 -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/arithmetic_operators.json +209 -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/cross_sectional_operators.json +98 -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/group_operators.json +121 -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/logical_operators.json +145 -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/reduce_operators.json +156 -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/special_operators.json +35 -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 +1 -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/time_series_operators.json +386 -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/transformational_operators.json +61 -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/vector_operators.json +38 -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/main.py +576 -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/process_knowledge_base.py +281 -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/rag_engine.py +408 -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/requirements.txt +7 -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/run.bat +3 -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/vector_db/_manifest.json +302 -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/vector_db/_meta.json +1 -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/vector_db/chroma.sqlite3 +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//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 +265 -0
- cnhkmcp/untracked/APP/.gitignore +32 -0
- cnhkmcp/untracked/APP/MODULAR_STRUCTURE.md +112 -0
- cnhkmcp/untracked/APP/README.md +309 -0
- cnhkmcp/untracked/APP/Tranformer/Transformer.py +4989 -0
- cnhkmcp/untracked/APP/Tranformer/ace.log +0 -0
- cnhkmcp/untracked/APP/Tranformer/ace_lib.py +1514 -0
- cnhkmcp/untracked/APP/Tranformer/helpful_functions.py +180 -0
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates.json +7187 -0
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates_/321/207/320/264/342/225/221/321/204/342/225/233/320/233.json +654 -0
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_error.json +1 -0
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_success.json +47312 -0
- 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 +22 -0
- cnhkmcp/untracked/APP/Tranformer/parsetab.py +60 -0
- cnhkmcp/untracked/APP/Tranformer/template_summary.txt +3182 -0
- cnhkmcp/untracked/APP/Tranformer/transformer_config.json +7 -0
- cnhkmcp/untracked/APP/Tranformer/validator.py +889 -0
- cnhkmcp/untracked/APP/ace.log +69 -0
- cnhkmcp/untracked/APP/ace_lib.py +1514 -0
- cnhkmcp/untracked/APP/blueprints/__init__.py +6 -0
- cnhkmcp/untracked/APP/blueprints/feature_engineering.py +347 -0
- cnhkmcp/untracked/APP/blueprints/idea_house.py +221 -0
- cnhkmcp/untracked/APP/blueprints/inspiration_house.py +432 -0
- cnhkmcp/untracked/APP/blueprints/paper_analysis.py +570 -0
- cnhkmcp/untracked/APP/custom_templates/templates.json +1257 -0
- cnhkmcp/untracked/APP/give_me_idea/BRAIN_Alpha_Template_Expert_SystemPrompt.md +400 -0
- cnhkmcp/untracked/APP/give_me_idea/ace_lib.py +1514 -0
- cnhkmcp/untracked/APP/give_me_idea/alpha_data_specific_template_master.py +252 -0
- cnhkmcp/untracked/APP/give_me_idea/fetch_all_datasets.py +157 -0
- cnhkmcp/untracked/APP/give_me_idea/fetch_all_operators.py +99 -0
- cnhkmcp/untracked/APP/give_me_idea/helpful_functions.py +180 -0
- cnhkmcp/untracked/APP/give_me_idea/what_is_Alpha_template.md +11 -0
- cnhkmcp/untracked/APP/helpful_functions.py +180 -0
- cnhkmcp/untracked/APP/hkSimulator/ace_lib.py +1501 -0
- cnhkmcp/untracked/APP/hkSimulator/autosimulator.py +447 -0
- cnhkmcp/untracked/APP/hkSimulator/helpful_functions.py +180 -0
- cnhkmcp/untracked/APP/mirror_config.txt +20 -0
- cnhkmcp/untracked/APP/operaters.csv +129 -0
- cnhkmcp/untracked/APP/requirements.txt +53 -0
- cnhkmcp/untracked/APP/run_app.bat +28 -0
- cnhkmcp/untracked/APP/run_app.sh +34 -0
- cnhkmcp/untracked/APP/setup_tsinghua.bat +39 -0
- cnhkmcp/untracked/APP/setup_tsinghua.sh +43 -0
- cnhkmcp/untracked/APP/simulator/alpha_submitter.py +404 -0
- cnhkmcp/untracked/APP/simulator/simulator_wqb.py +618 -0
- cnhkmcp/untracked/APP/ssrn-3332513.pdf +109188 -19
- cnhkmcp/untracked/APP/static/brain.js +589 -0
- cnhkmcp/untracked/APP/static/decoder.js +1540 -0
- cnhkmcp/untracked/APP/static/feature_engineering.js +1729 -0
- cnhkmcp/untracked/APP/static/idea_house.js +937 -0
- cnhkmcp/untracked/APP/static/inspiration.js +465 -0
- cnhkmcp/untracked/APP/static/inspiration_house.js +868 -0
- cnhkmcp/untracked/APP/static/paper_analysis.js +390 -0
- cnhkmcp/untracked/APP/static/script.js +3082 -0
- cnhkmcp/untracked/APP/static/simulator.js +597 -0
- cnhkmcp/untracked/APP/static/styles.css +3127 -0
- cnhkmcp/untracked/APP/static/usage_widget.js +508 -0
- cnhkmcp/untracked/APP/templates/alpha_inspector.html +511 -0
- cnhkmcp/untracked/APP/templates/feature_engineering.html +960 -0
- cnhkmcp/untracked/APP/templates/idea_house.html +564 -0
- cnhkmcp/untracked/APP/templates/index.html +932 -0
- cnhkmcp/untracked/APP/templates/inspiration_house.html +861 -0
- cnhkmcp/untracked/APP/templates/paper_analysis.html +91 -0
- cnhkmcp/untracked/APP/templates/simulator.html +343 -0
- cnhkmcp/untracked/APP/templates/transformer_web.html +580 -0
- cnhkmcp/untracked/APP/usage.md +351 -0
- 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 +1514 -0
- 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 +712 -0
- 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 +180 -0
- 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 +2460 -0
- cnhkmcp/untracked/__init__.py +0 -0
- cnhkmcp/untracked/arXiv_API_Tool_Manual.md +490 -0
- cnhkmcp/untracked/arxiv_api.py +229 -0
- cnhkmcp/untracked/back_up/forum_functions.py +998 -0
- cnhkmcp/untracked/back_up/platform_functions.py +2886 -0
- cnhkmcp/untracked/brain-consultant.md +31 -0
- cnhkmcp/untracked/forum_functions.py +407 -0
- 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 +407 -0
- 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 +2601 -0
- 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 +31 -0
- 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 +101 -0
- 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 +190 -0
- cnhkmcp/untracked/platform_functions.py +2601 -0
- cnhkmcp/untracked/sample_mcp_config.json +11 -0
- cnhkmcp/untracked/user_config.json +31 -0
- 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 +202 -0
- 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 +56 -0
- 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 +194 -0
- 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 +101 -0
- 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 +436 -0
- 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 +128 -0
- 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 +192 -0
- {cnhkmcp-2.1.3.dist-info → cnhkmcp-2.1.5.dist-info}/METADATA +1 -1
- cnhkmcp-2.1.5.dist-info/RECORD +192 -0
- cnhkmcp-2.1.5.dist-info/top_level.txt +1 -0
- cnhkmcp-2.1.3.dist-info/RECORD +0 -6
- cnhkmcp-2.1.3.dist-info/top_level.txt +0 -1
- {cnhkmcp-2.1.3.dist-info → cnhkmcp-2.1.5.dist-info}/WHEEL +0 -0
- {cnhkmcp-2.1.3.dist-info → cnhkmcp-2.1.5.dist-info}/entry_points.txt +0 -0
- {cnhkmcp-2.1.3.dist-info → cnhkmcp-2.1.5.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,712 @@
|
|
|
1
|
+
"""Quick utilities for BRAIN OS alpha inspection.
|
|
2
|
+
|
|
3
|
+
Features:
|
|
4
|
+
- Login with email/password (supports persona detection).
|
|
5
|
+
- Fetch submitted OS alphas (optional top N).
|
|
6
|
+
- Pull operator list and parse each alpha expression into operators and datafields.
|
|
7
|
+
- Query datafield detail to list other available region/settings combinations.
|
|
8
|
+
|
|
9
|
+
Note: For convenience, a test credential is wired for ad-hoc runs. Override via
|
|
10
|
+
env vars `BRAIN_USERNAME` and `BRAIN_PASSWORD` in real use.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import re
|
|
17
|
+
import json
|
|
18
|
+
import getpass
|
|
19
|
+
import itertools
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from typing import Dict, List, Optional, Sequence, Tuple, Union
|
|
22
|
+
import time
|
|
23
|
+
import requests
|
|
24
|
+
import pandas as pd
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
from ace_lib import start_simulation, simulation_progress, get_instrument_type_region_delay
|
|
28
|
+
except ImportError as e:
|
|
29
|
+
print(f"Warning: ace_lib.py not found or failed to import: {e}")
|
|
30
|
+
start_simulation = None
|
|
31
|
+
simulation_progress = None
|
|
32
|
+
get_instrument_type_region_delay = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
BASE_URL = "https://api.worldquantbrain.com"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def brain_login(username: str, password: str, max_retries: int = 3) -> requests.Session:
|
|
39
|
+
"""Authenticate against BRAIN API and return a live session.
|
|
40
|
+
|
|
41
|
+
Raises a RuntimeError if persona (biometric) auth is required so callers can
|
|
42
|
+
surface the URL to users.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
session = requests.Session()
|
|
46
|
+
session.auth = (username, password)
|
|
47
|
+
|
|
48
|
+
for attempt in range(1, max_retries + 1):
|
|
49
|
+
response = session.post(f"{BASE_URL}/authentication")
|
|
50
|
+
|
|
51
|
+
if response.status_code == requests.codes.unauthorized:
|
|
52
|
+
if response.headers.get("WWW-Authenticate") == "persona":
|
|
53
|
+
location = response.headers.get("Location", "")
|
|
54
|
+
raise RuntimeError(
|
|
55
|
+
"Biometric authentication required. Complete it in browser: "
|
|
56
|
+
f"{location}"
|
|
57
|
+
)
|
|
58
|
+
raise RuntimeError("Invalid username or password.")
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
response.raise_for_status()
|
|
62
|
+
return session
|
|
63
|
+
except requests.HTTPError as exc: # pragma: no cover - network path
|
|
64
|
+
if attempt >= max_retries:
|
|
65
|
+
raise exc
|
|
66
|
+
|
|
67
|
+
raise RuntimeError("Authentication failed after retries.")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def fetch_alphas_by_date_range(
|
|
71
|
+
session: requests.Session, start_date: str, end_date: str
|
|
72
|
+
) -> List[Dict]:
|
|
73
|
+
"""Return submitted (OS) alphas within the date range (inclusive).
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
start_date: Start date in YYYY-MM-DD format.
|
|
77
|
+
end_date: End date in YYYY-MM-DD format.
|
|
78
|
+
"""
|
|
79
|
+
print(f"Fetching alphas from {start_date} to {end_date}...")
|
|
80
|
+
|
|
81
|
+
# Ensure dates are comparable strings (ISO format works for string comparison)
|
|
82
|
+
# Append time to make full comparison easy
|
|
83
|
+
# User suggested format: 2025-11-01T04:00:00.000Z
|
|
84
|
+
start_iso = f"{start_date}T00:00:00Z"
|
|
85
|
+
end_iso = f"{end_date}T23:59:59Z"
|
|
86
|
+
|
|
87
|
+
alphas: List[Dict] = []
|
|
88
|
+
limit = 50
|
|
89
|
+
offset = 0
|
|
90
|
+
|
|
91
|
+
while True:
|
|
92
|
+
# Use server-side filtering for performance
|
|
93
|
+
params = {
|
|
94
|
+
"stage": "OS",
|
|
95
|
+
"order": "-dateSubmitted",
|
|
96
|
+
"limit": limit,
|
|
97
|
+
"offset": offset,
|
|
98
|
+
"dateSubmitted>": start_iso,
|
|
99
|
+
"dateSubmitted<": end_iso,
|
|
100
|
+
}
|
|
101
|
+
resp = session.get(f"{BASE_URL}/users/self/alphas", params=params)
|
|
102
|
+
resp.raise_for_status()
|
|
103
|
+
|
|
104
|
+
payload = resp.json()
|
|
105
|
+
results = payload.get("results", []) if isinstance(payload, dict) else payload
|
|
106
|
+
|
|
107
|
+
if not results:
|
|
108
|
+
break
|
|
109
|
+
|
|
110
|
+
alphas.extend(results)
|
|
111
|
+
|
|
112
|
+
offset += limit
|
|
113
|
+
total = payload.get("count", 0) if isinstance(payload, dict) else 0
|
|
114
|
+
|
|
115
|
+
if offset >= total or len(results) < limit:
|
|
116
|
+
break
|
|
117
|
+
|
|
118
|
+
return alphas
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def fetch_alphas_by_ids(
|
|
122
|
+
session: requests.Session, alpha_ids: List[str]
|
|
123
|
+
) -> List[Dict]:
|
|
124
|
+
"""Return submitted (OS) alphas by their IDs.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
alpha_ids: List of Alpha IDs.
|
|
128
|
+
"""
|
|
129
|
+
print(f"Fetching {len(alpha_ids)} alphas by ID...")
|
|
130
|
+
alphas: List[Dict] = []
|
|
131
|
+
|
|
132
|
+
for alpha_id in alpha_ids:
|
|
133
|
+
alpha_id = alpha_id.strip()
|
|
134
|
+
if not alpha_id:
|
|
135
|
+
continue
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
resp = session.get(f"{BASE_URL}/alphas/{alpha_id}")
|
|
139
|
+
resp.raise_for_status()
|
|
140
|
+
alpha = resp.json()
|
|
141
|
+
alphas.append(alpha)
|
|
142
|
+
except Exception as e:
|
|
143
|
+
print(f"Error fetching alpha {alpha_id}: {e}")
|
|
144
|
+
continue
|
|
145
|
+
|
|
146
|
+
return alphas
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def fetch_operators(session: requests.Session) -> List[Dict]:
|
|
150
|
+
"""Fetch full operator catalog."""
|
|
151
|
+
|
|
152
|
+
resp = session.get(f"{BASE_URL}/operators")
|
|
153
|
+
resp.raise_for_status()
|
|
154
|
+
operators = resp.json()
|
|
155
|
+
return operators if isinstance(operators, list) else []
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _dedupe(seq: Sequence[str]) -> List[str]:
|
|
159
|
+
seen = set()
|
|
160
|
+
ordered: List[str] = []
|
|
161
|
+
for item in seq:
|
|
162
|
+
if item not in seen:
|
|
163
|
+
seen.add(item)
|
|
164
|
+
ordered.append(item)
|
|
165
|
+
return ordered
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _extract_expression(alpha: Dict) -> Optional[str]:
|
|
169
|
+
"""Pick the first available expression/code from an alpha payload."""
|
|
170
|
+
|
|
171
|
+
for key in ("regular", "combo", "selection"):
|
|
172
|
+
block = alpha.get(key)
|
|
173
|
+
if isinstance(block, dict):
|
|
174
|
+
expr = block.get("expression") or block.get("code")
|
|
175
|
+
if isinstance(expr, str):
|
|
176
|
+
return expr
|
|
177
|
+
return None
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def parse_expression(
|
|
181
|
+
expression: str, operator_names: Sequence[str]
|
|
182
|
+
) -> Tuple[List[str], List[str]]:
|
|
183
|
+
"""Split an expression into operators and datafields using a token scan."""
|
|
184
|
+
|
|
185
|
+
# Remove C-style comments /* ... */
|
|
186
|
+
expression = re.sub(r"/\*[\s\S]*?\*/", "", expression)
|
|
187
|
+
# Remove Python-style comments # ...
|
|
188
|
+
expression = re.sub(r"#.*", "", expression)
|
|
189
|
+
|
|
190
|
+
operator_set = set(operator_names)
|
|
191
|
+
tokens = re.findall(r"[A-Za-z_][A-Za-z0-9_]*", expression)
|
|
192
|
+
|
|
193
|
+
found_ops: List[str] = []
|
|
194
|
+
found_fields: List[str] = []
|
|
195
|
+
|
|
196
|
+
skip_tokens = {"if", "else", "true", "false", "nan", "inf"}
|
|
197
|
+
|
|
198
|
+
for token in tokens:
|
|
199
|
+
if token in skip_tokens:
|
|
200
|
+
continue
|
|
201
|
+
if token in operator_set:
|
|
202
|
+
found_ops.append(token)
|
|
203
|
+
else:
|
|
204
|
+
found_fields.append(token)
|
|
205
|
+
|
|
206
|
+
return _dedupe(found_ops), _dedupe(found_fields)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def analyze_alphas(
|
|
210
|
+
alphas: Sequence[Dict], operators: Sequence[Dict]
|
|
211
|
+
) -> Dict[str, List[str]]:
|
|
212
|
+
"""Return combined operator and datafield lists for provided alphas."""
|
|
213
|
+
|
|
214
|
+
operator_names = [op.get("name", "") for op in operators if isinstance(op, dict)]
|
|
215
|
+
all_ops: List[str] = []
|
|
216
|
+
all_fields: List[str] = []
|
|
217
|
+
|
|
218
|
+
for alpha in alphas:
|
|
219
|
+
expr = _extract_expression(alpha)
|
|
220
|
+
if not expr:
|
|
221
|
+
continue
|
|
222
|
+
ops, fields = parse_expression(expr, operator_names)
|
|
223
|
+
all_ops.extend(ops)
|
|
224
|
+
all_fields.extend(fields)
|
|
225
|
+
|
|
226
|
+
return {"operators": _dedupe(all_ops), "datafields": _dedupe(all_fields)}
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def get_datafield_availability(
|
|
230
|
+
session: requests.Session,
|
|
231
|
+
field_name: str,
|
|
232
|
+
instrument_type: str = "EQUITY",
|
|
233
|
+
region: str = "USA",
|
|
234
|
+
delay: int = 1,
|
|
235
|
+
universe: str = "TOP3000",
|
|
236
|
+
) -> Dict[str, List[Dict]]:
|
|
237
|
+
"""Fetch detail for a datafield and summarize other available settings."""
|
|
238
|
+
|
|
239
|
+
params = {
|
|
240
|
+
"instrumentType": instrument_type,
|
|
241
|
+
"region": region,
|
|
242
|
+
"delay": delay,
|
|
243
|
+
"universe": universe,
|
|
244
|
+
}
|
|
245
|
+
time.sleep(2) # To avoid hitting rate limits
|
|
246
|
+
try:
|
|
247
|
+
resp = session.get(f"{BASE_URL}/data-fields/{field_name}", params=params)
|
|
248
|
+
resp.raise_for_status()
|
|
249
|
+
except requests.exceptions.HTTPError as e:
|
|
250
|
+
if e.response.status_code == 404:
|
|
251
|
+
return {"detail": {}, "availability": [], "error": "Datafield not found"}
|
|
252
|
+
raise e
|
|
253
|
+
detail = resp.json()
|
|
254
|
+
|
|
255
|
+
availability_candidates = []
|
|
256
|
+
for key in (
|
|
257
|
+
"availability",
|
|
258
|
+
"availabilities",
|
|
259
|
+
"availableSettings",
|
|
260
|
+
"availabilityList",
|
|
261
|
+
"regionAvailability",
|
|
262
|
+
"settings",
|
|
263
|
+
"data",
|
|
264
|
+
):
|
|
265
|
+
value = detail.get(key)
|
|
266
|
+
if isinstance(value, list):
|
|
267
|
+
availability_candidates.extend(value)
|
|
268
|
+
elif isinstance(value, dict):
|
|
269
|
+
nested = value.get("availability") or value.get("items") or value.get("list")
|
|
270
|
+
if isinstance(nested, list):
|
|
271
|
+
availability_candidates.extend(nested)
|
|
272
|
+
|
|
273
|
+
def _pick(d, keys):
|
|
274
|
+
for k in keys:
|
|
275
|
+
val = d.get(k)
|
|
276
|
+
if val is not None:
|
|
277
|
+
return val
|
|
278
|
+
return None
|
|
279
|
+
|
|
280
|
+
normalized = []
|
|
281
|
+
for item in availability_candidates:
|
|
282
|
+
if not isinstance(item, dict):
|
|
283
|
+
continue
|
|
284
|
+
normalized.append(
|
|
285
|
+
{
|
|
286
|
+
"instrumentType": _pick(item, ["instrumentType", "instrument_type"]) or instrument_type,
|
|
287
|
+
"region": _pick(item, ["region", "regionCode"]),
|
|
288
|
+
"delay": _pick(item, ["delay", "lag"]),
|
|
289
|
+
"universe": _pick(item, ["universe", "universeName"]),
|
|
290
|
+
}
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
# Deduplicate normalized combos.
|
|
294
|
+
normalized = _dedupe(
|
|
295
|
+
[json.dumps(x, sort_keys=True) for x in normalized if any(x.values())]
|
|
296
|
+
)
|
|
297
|
+
combos = [json.loads(x) for x in normalized]
|
|
298
|
+
|
|
299
|
+
return {"detail": detail, "availability": combos}
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def validate_setting(setting: Dict, options_df: Optional[pd.DataFrame]) -> bool:
|
|
303
|
+
"""Check if a setting combination is valid according to simulation options."""
|
|
304
|
+
if options_df is None or options_df.empty:
|
|
305
|
+
return True # Skip validation if options not available
|
|
306
|
+
|
|
307
|
+
inst_type = setting.get("instrumentType", "EQUITY")
|
|
308
|
+
region = setting.get("region")
|
|
309
|
+
delay = setting.get("delay")
|
|
310
|
+
universe = setting.get("universe")
|
|
311
|
+
neutralization = setting.get("neutralization")
|
|
312
|
+
|
|
313
|
+
try:
|
|
314
|
+
delay = int(delay)
|
|
315
|
+
except (ValueError, TypeError):
|
|
316
|
+
pass
|
|
317
|
+
|
|
318
|
+
# Iterate to find match
|
|
319
|
+
for _, row in options_df.iterrows():
|
|
320
|
+
row_inst = row.get('InstrumentType')
|
|
321
|
+
row_region = row.get('Region')
|
|
322
|
+
row_delay = row.get('Delay')
|
|
323
|
+
|
|
324
|
+
try:
|
|
325
|
+
row_delay = int(row_delay)
|
|
326
|
+
except (ValueError, TypeError):
|
|
327
|
+
pass
|
|
328
|
+
|
|
329
|
+
if row_inst == inst_type and row_region == region and row_delay == delay:
|
|
330
|
+
# Check universe
|
|
331
|
+
valid_universes = row.get('Universe', [])
|
|
332
|
+
if isinstance(valid_universes, list) and universe not in valid_universes:
|
|
333
|
+
return False
|
|
334
|
+
|
|
335
|
+
# Check neutralization if present in setting
|
|
336
|
+
if neutralization:
|
|
337
|
+
valid_neutralizations = row.get('Neutralization', [])
|
|
338
|
+
if isinstance(valid_neutralizations, list) and neutralization not in valid_neutralizations:
|
|
339
|
+
return False
|
|
340
|
+
|
|
341
|
+
return True
|
|
342
|
+
|
|
343
|
+
return False
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def find_common_availabilities(
|
|
347
|
+
session: requests.Session, datafields: List[str]
|
|
348
|
+
) -> List[Dict]:
|
|
349
|
+
"""Find the intersection of available settings for a list of datafields.
|
|
350
|
+
|
|
351
|
+
Returns a list of settings (region, universe, delay, instrumentType) that are
|
|
352
|
+
valid for ALL provided datafields.
|
|
353
|
+
"""
|
|
354
|
+
if not datafields:
|
|
355
|
+
return []
|
|
356
|
+
|
|
357
|
+
common_settings = None
|
|
358
|
+
|
|
359
|
+
for field in datafields:
|
|
360
|
+
# Fetch availability for this field
|
|
361
|
+
info = get_datafield_availability(session, field)
|
|
362
|
+
|
|
363
|
+
# If field not found or has no availability, we skip it.
|
|
364
|
+
# It might be a local variable, a constant, or a vector not in the catalog.
|
|
365
|
+
if info.get("error") or not info.get("availability"):
|
|
366
|
+
print(f"Field '{field}' has no availability info (likely local var). Skipping constraint.")
|
|
367
|
+
continue
|
|
368
|
+
|
|
369
|
+
# Convert availability list to a set of JSON strings for set intersection
|
|
370
|
+
# We use JSON strings because dicts are not hashable
|
|
371
|
+
current_settings = set()
|
|
372
|
+
for item in info["availability"]:
|
|
373
|
+
# Normalize keys to ensure consistent JSON representation
|
|
374
|
+
normalized_item = {
|
|
375
|
+
"instrumentType": item.get("instrumentType"),
|
|
376
|
+
"region": item.get("region"),
|
|
377
|
+
"delay": item.get("delay"),
|
|
378
|
+
"universe": item.get("universe"),
|
|
379
|
+
}
|
|
380
|
+
current_settings.add(json.dumps(normalized_item, sort_keys=True))
|
|
381
|
+
|
|
382
|
+
if common_settings is None:
|
|
383
|
+
common_settings = current_settings
|
|
384
|
+
else:
|
|
385
|
+
common_settings = common_settings.intersection(current_settings)
|
|
386
|
+
|
|
387
|
+
# Optimization: if intersection becomes empty, we can stop early
|
|
388
|
+
if not common_settings:
|
|
389
|
+
print(f"Intersection became empty after checking field '{field}'.")
|
|
390
|
+
return []
|
|
391
|
+
|
|
392
|
+
# If common_settings is still None, it means no fields returned valid availability.
|
|
393
|
+
if common_settings is None:
|
|
394
|
+
return []
|
|
395
|
+
|
|
396
|
+
# Convert back to list of dicts
|
|
397
|
+
result = [json.loads(s) for s in common_settings]
|
|
398
|
+
|
|
399
|
+
# Sort for consistent output (optional but nice)
|
|
400
|
+
result.sort(key=lambda x: (x.get("region", ""), x.get("universe", ""), x.get("delay", 0)))
|
|
401
|
+
|
|
402
|
+
return result
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
def get_alpha_variants(
|
|
406
|
+
session: requests.Session, alpha: Dict, operators: List[Dict], simulation_options: Optional[pd.DataFrame] = None
|
|
407
|
+
) -> Dict:
|
|
408
|
+
"""Analyze alpha and find valid setting variants without simulating."""
|
|
409
|
+
alpha_id = alpha.get("id", "Unknown")
|
|
410
|
+
alpha_type = alpha.get("type")
|
|
411
|
+
|
|
412
|
+
if alpha_type != "REGULAR":
|
|
413
|
+
return {"id": alpha_id, "valid": False, "reason": "Not REGULAR type", "variants": []}
|
|
414
|
+
|
|
415
|
+
expr = _extract_expression(alpha)
|
|
416
|
+
if not expr:
|
|
417
|
+
return {"id": alpha_id, "valid": False, "reason": "No expression found", "variants": []}
|
|
418
|
+
|
|
419
|
+
operator_names = [op.get("name", "") for op in operators if isinstance(op, dict)]
|
|
420
|
+
_, fields = parse_expression(expr, operator_names)
|
|
421
|
+
|
|
422
|
+
if not fields:
|
|
423
|
+
return {"id": alpha_id, "valid": False, "reason": "No datafields found", "variants": []}
|
|
424
|
+
|
|
425
|
+
common_settings = find_common_availabilities(session, fields)
|
|
426
|
+
|
|
427
|
+
if not common_settings:
|
|
428
|
+
return {"id": alpha_id, "valid": False, "reason": "No common settings", "variants": []}
|
|
429
|
+
|
|
430
|
+
original_settings = alpha.get("settings", {})
|
|
431
|
+
valid_variants = []
|
|
432
|
+
|
|
433
|
+
for new_setting in common_settings:
|
|
434
|
+
# Construct full simulation payload (merge first to validate full settings)
|
|
435
|
+
merged_settings = original_settings.copy()
|
|
436
|
+
merged_settings.update(new_setting)
|
|
437
|
+
|
|
438
|
+
# Validate against simulation options if provided
|
|
439
|
+
if simulation_options is not None:
|
|
440
|
+
if not validate_setting(merged_settings, simulation_options):
|
|
441
|
+
continue
|
|
442
|
+
|
|
443
|
+
# Check duplicate
|
|
444
|
+
is_duplicate = True
|
|
445
|
+
for key in ["region", "universe", "delay", "instrumentType"]:
|
|
446
|
+
val_orig = str(original_settings.get(key, ""))
|
|
447
|
+
val_new = str(new_setting.get(key, ""))
|
|
448
|
+
if val_orig != val_new:
|
|
449
|
+
is_duplicate = False
|
|
450
|
+
break
|
|
451
|
+
|
|
452
|
+
if not is_duplicate:
|
|
453
|
+
# Ensure required fields for ace_lib compatibility if missing
|
|
454
|
+
if "language" not in merged_settings:
|
|
455
|
+
merged_settings["language"] = "FASTEXPR"
|
|
456
|
+
|
|
457
|
+
# Add maxTrade: ON for specific regions
|
|
458
|
+
# if merged_settings.get("region") in ["ASI", "JPN", "HKG", "KOR", "TWN"]:
|
|
459
|
+
# merged_settings["maxTrade"] = "ON"
|
|
460
|
+
|
|
461
|
+
payload = {
|
|
462
|
+
"type": "REGULAR",
|
|
463
|
+
"settings": merged_settings,
|
|
464
|
+
"regular": expr,
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
valid_variants.append({
|
|
468
|
+
"diff_settings": new_setting,
|
|
469
|
+
"simulation_payload": payload
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
return {
|
|
473
|
+
"id": alpha_id,
|
|
474
|
+
"dateSubmitted": alpha.get("dateSubmitted"),
|
|
475
|
+
"expression": expr,
|
|
476
|
+
"valid": True,
|
|
477
|
+
"variants": valid_variants,
|
|
478
|
+
"original_settings": original_settings
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def run_simulation_payload(
|
|
483
|
+
session: requests.Session,
|
|
484
|
+
payload: Dict,
|
|
485
|
+
) -> Tuple[bool, Union[Dict, str]]:
|
|
486
|
+
"""Send a simulation request and wait for the result.
|
|
487
|
+
|
|
488
|
+
Returns: (success, result_or_error_message)
|
|
489
|
+
"""
|
|
490
|
+
if not start_simulation or not simulation_progress:
|
|
491
|
+
return False, "Simulation tools (ace_lib) not available or failed to import."
|
|
492
|
+
|
|
493
|
+
settings = payload.get("settings", {})
|
|
494
|
+
print(f" -> Submitting simulation for {settings.get('region')} / {settings.get('universe')}...")
|
|
495
|
+
|
|
496
|
+
try:
|
|
497
|
+
resp = start_simulation(session, payload)
|
|
498
|
+
|
|
499
|
+
# Check if response is valid (status code 200-299)
|
|
500
|
+
if not resp.ok:
|
|
501
|
+
error_msg = f"Simulation API Error: {resp.status_code} - {resp.text}"
|
|
502
|
+
print(f" -> {error_msg}")
|
|
503
|
+
return False, error_msg
|
|
504
|
+
|
|
505
|
+
result = simulation_progress(session, resp)
|
|
506
|
+
if result.get("completed"):
|
|
507
|
+
return True, result.get("result")
|
|
508
|
+
else:
|
|
509
|
+
msg = result.get("message") or "Simulation failed or incomplete."
|
|
510
|
+
print(f" -> {msg}")
|
|
511
|
+
return False, msg
|
|
512
|
+
except Exception as e:
|
|
513
|
+
import traceback
|
|
514
|
+
traceback.print_exc()
|
|
515
|
+
print(f" -> Error during simulation: {e}")
|
|
516
|
+
return False, str(e)
|
|
517
|
+
|
|
518
|
+
# Deprecated but kept for compatibility if needed
|
|
519
|
+
def run_simulation_for_setting(
|
|
520
|
+
session: requests.Session,
|
|
521
|
+
expression: str,
|
|
522
|
+
settings: Dict,
|
|
523
|
+
) -> Optional[Dict]:
|
|
524
|
+
payload = {
|
|
525
|
+
"type": "REGULAR",
|
|
526
|
+
"settings": settings,
|
|
527
|
+
"regular": expression,
|
|
528
|
+
}
|
|
529
|
+
success, res = run_simulation_payload(session, payload)
|
|
530
|
+
return res if success else None
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def process_alpha_variants(
|
|
534
|
+
session: requests.Session, alpha: Dict, operators: List[Dict], simulation_options: Optional[pd.DataFrame] = None
|
|
535
|
+
) -> List[Dict]:
|
|
536
|
+
"""Analyze alpha, find common availabilities, and simulate variants.
|
|
537
|
+
|
|
538
|
+
Returns a list of simulation results (new alphas).
|
|
539
|
+
"""
|
|
540
|
+
generated_alphas = []
|
|
541
|
+
|
|
542
|
+
alpha_id = alpha.get("id", "Unknown")
|
|
543
|
+
alpha_type = alpha.get("type")
|
|
544
|
+
|
|
545
|
+
if alpha_type != "REGULAR":
|
|
546
|
+
print(f"Skipping Alpha {alpha_id}: Type is {alpha_type}, not REGULAR.")
|
|
547
|
+
return []
|
|
548
|
+
|
|
549
|
+
print(f"\nProcessing Alpha {alpha_id}...")
|
|
550
|
+
|
|
551
|
+
# Extract expression
|
|
552
|
+
expr = _extract_expression(alpha)
|
|
553
|
+
if not expr:
|
|
554
|
+
print(" -> No expression found.")
|
|
555
|
+
return []
|
|
556
|
+
|
|
557
|
+
# Parse datafields
|
|
558
|
+
operator_names = [op.get("name", "") for op in operators if isinstance(op, dict)]
|
|
559
|
+
_, fields = parse_expression(expr, operator_names)
|
|
560
|
+
|
|
561
|
+
if not fields:
|
|
562
|
+
print(" -> No datafields found to check availability.")
|
|
563
|
+
return []
|
|
564
|
+
|
|
565
|
+
# Find common availabilities
|
|
566
|
+
print(f" -> Checking availability for {len(fields)} fields...")
|
|
567
|
+
common_settings = find_common_availabilities(session, fields)
|
|
568
|
+
|
|
569
|
+
if not common_settings:
|
|
570
|
+
print(" -> No common settings found.")
|
|
571
|
+
return []
|
|
572
|
+
|
|
573
|
+
print(f" -> Found {len(common_settings)} valid setting combinations.")
|
|
574
|
+
|
|
575
|
+
# Base settings from original alpha
|
|
576
|
+
original_settings = alpha.get("settings", {})
|
|
577
|
+
|
|
578
|
+
for i, new_setting in enumerate(common_settings):
|
|
579
|
+
print(f"\n [Variant {i+1}/{len(common_settings)}]")
|
|
580
|
+
|
|
581
|
+
# Merge settings: keep original unless overwritten by new availability
|
|
582
|
+
# Availability gives: region, universe, delay, instrumentType
|
|
583
|
+
# Original has: decay, neutralization, truncation, etc.
|
|
584
|
+
merged_settings = original_settings.copy()
|
|
585
|
+
merged_settings.update(new_setting)
|
|
586
|
+
|
|
587
|
+
# Validate against simulation options if provided
|
|
588
|
+
if simulation_options is not None:
|
|
589
|
+
if not validate_setting(merged_settings, simulation_options):
|
|
590
|
+
print(f" -> Skipping: Invalid simulation setting combination ({new_setting.get('region')}/{new_setting.get('universe')}).")
|
|
591
|
+
continue
|
|
592
|
+
|
|
593
|
+
# Check if this variant duplicates the original alpha's settings
|
|
594
|
+
is_duplicate = True
|
|
595
|
+
for key in ["region", "universe", "delay", "instrumentType"]:
|
|
596
|
+
# Compare as strings to handle potential type mismatches (e.g. delay int vs str)
|
|
597
|
+
val_orig = str(original_settings.get(key, ""))
|
|
598
|
+
val_new = str(new_setting.get(key, ""))
|
|
599
|
+
if val_orig != val_new:
|
|
600
|
+
is_duplicate = False
|
|
601
|
+
break
|
|
602
|
+
|
|
603
|
+
if is_duplicate:
|
|
604
|
+
print(f" -> Skipping: Settings match original alpha ({new_setting.get('region')}/{new_setting.get('universe')}).")
|
|
605
|
+
continue
|
|
606
|
+
|
|
607
|
+
# Add maxTrade: ON for specific regions
|
|
608
|
+
# if merged_settings.get("region") in ["ASI", "JPN", "HKG", "KOR", "TWN"]:
|
|
609
|
+
# merged_settings["maxTrade"] = "ON"
|
|
610
|
+
|
|
611
|
+
# Run simulation
|
|
612
|
+
result = run_simulation_for_setting(session, expr, merged_settings)
|
|
613
|
+
|
|
614
|
+
if result:
|
|
615
|
+
# Print some stats
|
|
616
|
+
stats = result.get("is", {})
|
|
617
|
+
sharpe = stats.get("sharpe", "N/A")
|
|
618
|
+
returns = stats.get("returns", "N/A")
|
|
619
|
+
turnover = stats.get("turnover", "N/A")
|
|
620
|
+
new_alpha_id = result.get("id")
|
|
621
|
+
print(f" -> Result: ID={new_alpha_id}, Sharpe={sharpe}, Returns={returns}, Turnover={turnover}")
|
|
622
|
+
|
|
623
|
+
# Add metadata about origin
|
|
624
|
+
result["_origin_alpha_id"] = alpha_id
|
|
625
|
+
result["_origin_variant_settings"] = new_setting
|
|
626
|
+
generated_alphas.append(result)
|
|
627
|
+
|
|
628
|
+
return generated_alphas
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
def main() -> None:
|
|
632
|
+
"""Interactive main function."""
|
|
633
|
+
print("=== BRAIN Alpha Variant Generator ===")
|
|
634
|
+
|
|
635
|
+
# 1. Interactive Login
|
|
636
|
+
username = input("Enter BRAIN Username (Email): ").strip()
|
|
637
|
+
if not username:
|
|
638
|
+
print("Username is required.")
|
|
639
|
+
return
|
|
640
|
+
|
|
641
|
+
password = getpass.getpass("Enter BRAIN Password: ").strip()
|
|
642
|
+
if not password:
|
|
643
|
+
print("Password is required.")
|
|
644
|
+
return
|
|
645
|
+
|
|
646
|
+
try:
|
|
647
|
+
print(f"Logging in as {username}...")
|
|
648
|
+
session = brain_login(username, password)
|
|
649
|
+
print("Login successful.")
|
|
650
|
+
except Exception as e:
|
|
651
|
+
print(f"Login failed: {e}")
|
|
652
|
+
return
|
|
653
|
+
|
|
654
|
+
# 2. Date Range
|
|
655
|
+
print("\n--- Date Range Selection ---")
|
|
656
|
+
start_date = input("Enter Start Date (YYYY-MM-DD): ").strip()
|
|
657
|
+
end_date = input("Enter End Date (YYYY-MM-DD): ").strip()
|
|
658
|
+
|
|
659
|
+
# Basic validation
|
|
660
|
+
try:
|
|
661
|
+
datetime.strptime(start_date, "%Y-%m-%d")
|
|
662
|
+
datetime.strptime(end_date, "%Y-%m-%d")
|
|
663
|
+
except ValueError:
|
|
664
|
+
print("Invalid date format. Please use YYYY-MM-DD.")
|
|
665
|
+
return
|
|
666
|
+
|
|
667
|
+
# Fetch Alphas
|
|
668
|
+
alphas = fetch_alphas_by_date_range(session, start_date, end_date)
|
|
669
|
+
print(f"Fetched {len(alphas)} alphas from {start_date} to {end_date}.")
|
|
670
|
+
|
|
671
|
+
if not alphas:
|
|
672
|
+
print("No alphas found in this range. Exiting.")
|
|
673
|
+
return
|
|
674
|
+
|
|
675
|
+
print("Fetching operator catalog...")
|
|
676
|
+
operators = fetch_operators(session)
|
|
677
|
+
|
|
678
|
+
print("Fetching simulation options...")
|
|
679
|
+
simulation_options = None
|
|
680
|
+
if get_instrument_type_region_delay:
|
|
681
|
+
try:
|
|
682
|
+
simulation_options = get_instrument_type_region_delay(session)
|
|
683
|
+
print("Simulation options fetched successfully.")
|
|
684
|
+
except Exception as e:
|
|
685
|
+
print(f"Warning: Failed to fetch simulation options: {e}")
|
|
686
|
+
else:
|
|
687
|
+
print("Warning: get_instrument_type_region_delay not available.")
|
|
688
|
+
|
|
689
|
+
# 3. Process Alphas
|
|
690
|
+
all_generated_alphas = []
|
|
691
|
+
|
|
692
|
+
for i, alpha in enumerate(alphas):
|
|
693
|
+
new_alphas = process_alpha_variants(session, alpha, operators, simulation_options)
|
|
694
|
+
all_generated_alphas.extend(new_alphas)
|
|
695
|
+
|
|
696
|
+
# 4. Output
|
|
697
|
+
if all_generated_alphas:
|
|
698
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
699
|
+
filename = f"generated_alphas_{timestamp}.json"
|
|
700
|
+
|
|
701
|
+
print(f"\nTotal generated alphas: {len(all_generated_alphas)}")
|
|
702
|
+
print(f"Saving results to {filename}...")
|
|
703
|
+
|
|
704
|
+
with open(filename, "w", encoding="utf-8") as f:
|
|
705
|
+
json.dump(all_generated_alphas, f, indent=2, ensure_ascii=False)
|
|
706
|
+
|
|
707
|
+
print("Done.")
|
|
708
|
+
else:
|
|
709
|
+
print("\nNo new alphas were generated.")
|
|
710
|
+
|
|
711
|
+
if __name__ == "__main__":
|
|
712
|
+
main()
|