This commit is contained in:
Xu Yang 2023-07-17 20:33:47 +08:00
Родитель 8c1905d1d7
Коммит 13c63eee0a
7 изменённых файлов: 349 добавлений и 168 удалений

3
.gitignore поставляемый
Просмотреть файл

@ -23,6 +23,9 @@ qlib/VERSION.txt
qlib/data/_libs/expanding.cpp
qlib/data/_libs/rolling.cpp
qlib/finco/prompt_cache.json
qlib/finco/finco_workspace/
qlib/finco/knowledge/*/knowledge.pkl
qlib/finco/knowledge/*/storage.yml
examples/estimator/estimator_example/
examples/rl/data/
examples/rl/checkpoints/

Просмотреть файл

@ -76,14 +76,14 @@ class YamlStorage(Storage):
def load(self):
"""load data from yaml format file"""
try:
self.documents = yaml.load(open(self.path, "r"), Loader=yaml.FullLoader)
self.documents = yaml.safe_load(self.path.open())
except FileNotFoundError:
logger.warning(f"YamlStorage: file {self.path} doesn't exist.")
def save(self, **kwargs):
"""use pickle as the default save method"""
Path.mkdir(self.path.parent, exist_ok=True)
with open(self.path, "w") as f:
Path.mkdir(self.path.parent, exist_ok=True, parents=True)
with open(self.path, 'w') as f:
yaml.dump(self.documents, f)
@ -435,26 +435,22 @@ class KnowledgeBase(SingletonBaseClass):
def load_practice_knowledge(self, path: Path) -> PracticeKnowledge:
self.practice_knowledge = PracticeKnowledge(
YamlStorage(path.joinpath(f"{self.KT_PRACTICE}/{YamlStorage.DEFAULT_NAME}"))
)
YamlStorage(path.joinpath(Path.cwd().joinpath("knowledge")/f"{self.KT_PRACTICE}/{YamlStorage.DEFAULT_NAME}")))
return self.practice_knowledge
def load_execute_knowledge(self, path: Path) -> ExecuteKnowledge:
self.execute_knowledge = ExecuteKnowledge(
YamlStorage(path.joinpath(f"{self.KT_EXECUTE}/{YamlStorage.DEFAULT_NAME}"))
)
YamlStorage(path.joinpath(Path.cwd().joinpath("knowledge")/f"{self.KT_EXECUTE}/{YamlStorage.DEFAULT_NAME}")))
return self.execute_knowledge
def load_finance_knowledge(self, path: Path) -> FinanceKnowledge:
self.finance_knowledge = FinanceKnowledge(
YamlStorage(path.joinpath(f"{self.KT_FINANCE}/{YamlStorage.DEFAULT_NAME}"))
)
YamlStorage(path.joinpath(Path.cwd().joinpath("knowledge")/f"{self.KT_FINANCE}/{YamlStorage.DEFAULT_NAME}")))
return self.finance_knowledge
def load_infrastructure_knowledge(self, path: Path) -> InfrastructureKnowledge:
self.infrastructure_knowledge = InfrastructureKnowledge(
YamlStorage(path.joinpath(f"{self.KT_INFRASTRUCTURE}/{YamlStorage.DEFAULT_NAME}"))
)
YamlStorage(path.joinpath(Path.cwd().joinpath("knowledge")/f"{self.KT_INFRASTRUCTURE}/{YamlStorage.DEFAULT_NAME}")))
return self.infrastructure_knowledge
def get_knowledge(self, knowledge_type: str = None):
@ -498,12 +494,12 @@ class KnowledgeBase(SingletonBaseClass):
similar_n_docs = [knowledge[i] for i in similar_n_indexes]
prompt = Template(
"""find the most relevant doc with this query: '{{content}}'
from docs='{{docs}}. Just return the most relevant item I provided, no more explain.
For example:
user: find the most relevant doc with this query: ab \n from docs = {abc, xyz, lmn}.
response: abc
"""
"""
find the most relevant doc with this query: '{{content}}' from docs='{{docs}}'.
Just return the most relevant item I provided, no more explain.
please treat the docs as sentences and always response no less than 5 relevant sentences.
List all the relevant sentences in number index without any interaction and conversation.
"""
)
prompt_workflow_selection = prompt.render(content=content, docs=similar_n_docs)
response = APIBackend().build_messages_and_create_chat_completion(

Просмотреть файл

@ -0,0 +1,45 @@
Quantitative investment research, often referred to as "quant," is an investment approach that uses mathematical and statistical models to analyze financial data and identify investment opportunities. This method relies heavily on computer algorithms and advanced data analysis techniques to develop trading strategies and make investment decisions.
One of the key aspects of quant investment research is the development of predictive models to forecast asset prices, market movements, and other financial variables. These models are typically built using historical data and refined through rigorous testing and validation processes.
In quant investment research, various metrics are used to evaluate the performance of a model or strategy. Some common metrics include annual return, information coefficient, maximum drawdown, and cumulative sum (cumsum) return.
Annual return is a measure of an investment's performance over the course of a year and is expressed as a percentage. It is an important metric to consider but can be controversial as higher annual returns are often associated with higher risks.
Maximum drawdown is the largest peak-to-trough decline in an investment's value over a specified period. It is a measure of the strategy's risk and can be controversial since increasing annual return often leads to a more dynamic strategy with larger drawdowns.
Information coefficient (IC) is a measure of the relationship between predicted returns and actual returns. A higher IC indicates a stronger relationship and suggests a more effective predictive model.
Cumulative sum return is the total return generated by an investment over a given period. It is useful for evaluating the overall performance of a strategy and is particularly relevant when comparing multiple strategies over the same time frame.
Another important aspect of quant investment research is portfolio optimization, which involves determining the optimal allocation of assets to maximize returns while minimizing risk.
Quantitative researchers often use techniques such as factor analysis to identify underlying drivers of asset returns. This helps them to build more robust models and better understand the relationships between various financial variables.
Machine learning has become increasingly popular in quant investment research, as it offers new ways to identify patterns and relationships in large datasets. Techniques such as neural networks, decision trees, and clustering algorithms are commonly used in this field.
Backtesting is a critical step in the development of a quantitative investment strategy. It involves applying a model or algorithm to historical data to see how it would have performed under various market conditions.
Risk management is a crucial component of quant investment research. Quantitative researchers must carefully consider the potential risks associated with their models and strategies and take steps to mitigate these risks.
In recent years, there has been a growing interest in alternative data sources for quant investment research. These can include social media sentiment, satellite imagery, and other non-traditional data sources that may provide unique insights into market trends and investment opportunities.
Despite its reliance on data and mathematical models, quant investment research is not without its challenges and limitations. Some critics argue that it is inherently backward-looking, as it relies on historical data to make predictions about future market movements.
Furthermore, quant models may struggle to adapt to rapidly changing market conditions and may be susceptible to overfitting, which occurs when a model is tailored too closely to the training data and performs poorly on new, unseen data.
In conclusion, quantitative investment research is a growing field that combines advanced mathematical and statistical techniques with financial expertise to develop sophisticated investment strategies and models. While it offers significant potential for generating returns and managing risk, it also comes with its own set of challenges and limitations that must be carefully considered.
A rolling meta-controller is a valuable tool in quantitative investment research, providing several benefits such as increased adaptability, enhanced risk management, and improved performance. By continuously updating the parameters of underlying trading models based on recent data, this approach helps strategies stay relevant in dynamic market conditions and reduces the risk of overfitting. Additionally, a rolling meta-controller can manage a diverse portfolio of trading models, leading to a more robust and diversified investment strategy.
However, incorporating a rolling meta-controller also comes with potential challenges, such as increased complexity, higher computational requirements, and the risk of parameter instability. It is essential for quantitative researchers to carefully weigh these factors when deciding whether to include a rolling meta-controller in their trading strategies. By balancing the potential advantages and disadvantages, researchers can optimize their strategies to achieve their specific investment objectives and risk tolerances.
Meta controller like rolling or DDGDA is proved to be relevant to the maximum drawdown but effect is still unknown. Because seeing the latest data is always good to avoid some new patterns recently. A static model is not good at doing it.
DDG-DA, which stands for Data Distribution Generation for Predictable Concept Drift Adaptation, is a research paper focused on addressing the challenge of concept drift in machine learning and data mining. Concept drift occurs when the statistical properties of a target variable change over time, causing the model's performance to degrade. This is a common issue in various domains, including finance, where market conditions and economic factors can change rapidly.
The DDG-DA paper proposes a framework for generating synthetic datasets that simulate concept drift in a controlled and predictable manner. By creating these datasets, researchers can better understand how concept drift affects the performance of their machine learning models and develop strategies for adapting to these changes.
The main idea behind DDG-DA is to create synthetic data distributions that mimic the underlying data generating process while controlling the extent of concept drift. This is achieved by using a combination of data transformation techniques, such as scaling, rotation, and translation of the original data distribution.
By generating synthetic datasets with controlled concept drift, researchers can evaluate and compare the performance of various adaptation techniques in a more systematic and controlled manner. This can lead to the development of more robust and adaptive machine learning models that can better handle changing data distributions, ultimately improving the performance of these models in real-world applications, such as finance and investment.

Просмотреть файл

@ -67,12 +67,6 @@ class APIBackend(SingletonBaseClass):
print(f"Retrying {i+1}th time...")
time.sleep(1)
continue
except openai.InvalidRequestError as e:
print("Invalid request, will try to reduce the messages length and retry...")
if len(kwargs["messages"]) > 2:
kwargs["messages"] = kwargs["messages"][[0]] + kwargs["messages"][3:]
continue
raise e
raise Exception(f"Failed to create chat completion after {max_retry} retries.")
def create_chat_completion(

Просмотреть файл

@ -18,10 +18,58 @@ WorkflowTask_system : |-
workflow: reinforcement learning
WorkflowTask_user : |-
User input: '{{user_prompt}}'
User input: '{{user_intention}}'
Please provide the workflow in Qlib (supervised learning or reinforcement learning) ensureing the workflow can meet the user's requirements.
Response only with the output in the exact format specified in the system prompt, with no explanation or conversation.
IdeaTask_system : |-
You are an Quant investment Research and development assistant whose job is to determine user's research intention at high level.
You should first understand user's intention, then decide the target from the intention. To fulfill the target, you should design the deliverable to meet the intention which is often a quantitative investment strategy including a model learned from finance dataset.
You should also provide the thinking direction of the research topic, which includes two directions: algorithm level and business level. Algorithm level means which workflow(supervised or reinforcement learning) do you plan to use to build the system. Notice, we often use reinforcement learning on minute frequency trading or order frequency. Daily frequency often requires a supervised learning workflow. Business level means which part of a quant investment system (data, model or strategy) do you want to target in the system and any custom controller (for example meta controller like rolling or DDGDA) you plan to choose in the system. custome controller choice is necessary even when you don't use any of them. Finally, you should give a simple sentence to explain your thinking direction.
User will first give you some knowledge from user's past experience. You should stick to these knowledge if you think these knowledge is helpful. Knowledge includes two types: practice knowledge and finance knowledge. Practice knowledge is the experience from former experiments, which might be empty. Finance knowledge is some sentences from research report or common sense. Practical knowledge is proved to be right while finance knowledge should be checked through your own knowledge.
Notice:
DDGDA is often used when rolling is proved to be working. So we firstly do research on rolling, then when we got the practice knowledge that rolling is helpful, then we can do research on DDGDA.
We often start to run rolling or DDGDA on very small model like linear model.
Rolling or DDGDA is a kind of data controller which applys custom weight to data in time dimention. So set Data as target module when rolling or DDGDA is used in business level. Never do research both on rolling or DDGDA.
We often use linear model as default model supervised learning because it trains very fast. If the user didn't plan to achieve very high accuracy, use default model and datahandler is a good choice to save time.
User will tell you the knowledge type and content in the conversation, if user said "following lists the {practice or finance} knowledge:", you should memorize and understand them then answer "OK" without any other words, finally, user will tell you the research intention, you should answer exactly the same format as the input without any interaction or conversation.
Example input:
Input 1:
following lists the practice knowledge:
Output 1:
OK
Input 2:
following lists the finance knowledge:
Output 2:
OK
Input 3:
Research intention:
build an US stock market daily portfolio in quantitative investment and maximize the excess return.
Output 3:
Target: maximize the excess return
Deliverables: a daily quantitative investment strategy in US stock market. A model will be included in the strategy.
Thinking directions:
Business level:
Controller: no custom controller
target module: Model
Algorithm level: supervised learning
Details:
Because the user wants to maximize the excess return and more complicated model often extracts more deep pattern from the data. So try a more complicated DNN model to get more excess return than a simple linear model.
IdeaTask_user : |-
pass
HighLevelPlanTask_system: |-
You are an Quant investment Research and development assistant whose job is to determine high level plans to testify user's research intention.
@ -31,15 +79,16 @@ HighLevelPlanTask_system: |-
Secondly, you need to design several comparable experiments to testify your idea, the experiments differ only in one or two small hyperparameters. You should also determine several metrics and comparing the metrics of each experiment can lead to a conclusion which meets user's target.
When designing the experiments, you should use control variates strategy and always design a simple baseline model and another comparable experiment. The simple baseline is crucial to measure the other experiments by comparing them with the baseline. So only two experiments are targeted and the simple baseline experiment is the first one.
When designing the experiments, you should use control variates strategy and always design a simple baseline model and another comparable experiment. The simple baseline is crucial to measure the other experiments by comparing them with the baseline. So only two experiments are targeted. The simple baseline experiment is the first one.
Notice: You should only design two experiments with only one simple difference (hyperparameter or training controller like rolling or meta controlling).
You can choose the suitable 'dataset', 'datahandler', 'model' module in qlib to design the experiments and the module candidates are:
Dataset: {qlib.data.dataset}-{DatasetH}, {qlib.contrib.data.dataset}-{MTSDatasetH}
DataHandler: {qlib.contrib.data.handler}-{Alpha158}, {qlib.contrib.data.handler}-{Alpha158vwap}, {qlib.contrib.data.handler}-{Alpha360}, {qlib.contrib.data.handler}-{Alpha360vwap}, {qlib.data.dataset.loader}-{QlibDataLoader}
DataHandler: {qlib.contrib.data.handler}-{Alpha158}, {qlib.contrib.data.handler}-{Alpha360}
Model: {qlib.contrib.model.catboost_model}-{CatBoostModel}, {qlib.contrib.model.double_ensemble}-{DoubleEnsembleModel}, {qlib.contrib.model.gbdt}-{LGBModel}, {qlib.contrib.model.highfreq_gdbt_model}-{HFLGBModel}, {qlib.contrib.model.linear}-{LinearModel}, {qlib.contrib.model.pytorch_adarnn}-{AdaRNNModel}, {qlib.contrib.model.pytorch_add}-{ADD}, {qlib.contrib.model.pytorch_alstm_ts}-{ALSTM}, {qlib.contrib.model.pytorch_alstm}-{ALSTM}, {qlib.contrib.model.pytorch_gats}-{GATs}, {qlib.contrib.model.pytorch_gats_ts}-{GATs}, {qlib.contrib.model.pytorch_gru}-{GRU}, {qlib.contrib.model.pytorch_gru_ts}-{GRU}, {qlib.contrib.model.pytorch_hist}-{HIST}, {qlib.contrib.model.pytorch_igmtf}-{IGMTF}, {qlib.contrib.model.pytorch_localformer}-{LocalformerModel}, {qlib.contrib.model.pytorch_localformer_ts}-{LocalformerModel}, {qlib.contrib.model.pytorch_lstm}-{LSTM}, {qlib.contrib.model.pytorch_lstm_ts}-{LSTM}, {qlib.contrib.model.pytorch_nn}-{DNNModelPytorch}, {qlib.contrib.model.pytorch_sfm}-{SFM}, {qlib.contrib.model.pytorch_tabnet}-{TabnetModel}, {qlib.contrib.model.pytorch_tcn_ts}-{TCN}, {qlib.contrib.model.pytorch_tcn}-{TCN}, {qlib.contrib.model.pytorch_tcts.}-{TCTS}, {qlib.contrib.model.pytorch_tra}-{TRA}, {qlib.contrib.model.pytorch_transformer}-{TransformerModel}, {qlib.contrib.model.pytorch_transformer_ts}-{TransformerModel}, {qlib.contrib.model.xgboost}-{XGBModel}
If you choose the module above, you should always pick from the list instead of making new names.
Caution, {qlib.contrib.data.dataset}-{MTSDatasetH} works with {qlib.contrib.model.pytorch_tra}-{TRA} together, do not use any of them alone in the experiment!
If you choose the module above, you should always pick from the list instead of making new names.
Please provide the output in the following format:
workflow: [supervised learning/reinforcement learning],
@ -50,7 +99,14 @@ HighLevelPlanTask_system: |-
Please note that your response should be based solely on the user's requirements and should consider factors such as the complexity of the task, the type and amount of data available, and the desired outcome.
Information: We often use linear model as default model in supervised learning because it trains very fast.
Information:
We often use linear model as default model and alpha158 as default datahandler in supervised learning because it trains very fast. If the user didn't plan to achieve very high accuracy, use default model and datahandler is a good choice to save time.
If you plan to use rolling as the controller, rolling itself can be an independent task, so no need to target any other target in you response.
Caution:
You don't need to follow the exsample to design different model when user doesn't target Model in target module.
If the user uses rolling or DDGDA as controller, you should design two experiments including a static model without rolling as baseline and another same experiment with rolling or DDGDA as meta controller.
Don't use MTSDatasetH when you choose LinearModel!!!
Your answer should strictly follow the infrastructure of Qlib and experiments and metrics are easy to get from the implementation of Qlib. You should also follow the format as example input and output.
@ -59,8 +115,10 @@ HighLevelPlanTask_system: |-
Target: maximize the excess return
Deliverables: a daily quantitative investment strategy in US stock market. A model will be included in the strategy.
Thinking directions:
1. Business level: Model
2. Algorithm level: supervised learning
Business level:
Controller: no custom controller
Target module: Model
Algorithm level: supervised learning
Details:
Because the user wants to maximize the excess return and more complicated model often extracts more deep pattern from the data. So try a more complicated DNN model to get more excess return than a simple linear model
@ -79,7 +137,8 @@ HighLevelPlanTask_user: |-
Target: {{ target }}
Deliverables: {{ deliverables }}
Thinking directions:
Business level: {{ business_level }}
Business level:
{{ business_level }}
Algorithm level: {{ algorithm_level }}
Details:
{{ thinking_detail }}
@ -93,14 +152,13 @@ SLPlanTask_system : |-
The predefined class in Qlib modules can be listed in format of {module_path}-{class name}:
Dataset: {qlib.data.dataset}-{DatasetH}, {qlib.contrib.data.dataset}-{MTSDatasetH}
DataHandler: {qlib.contrib.data.handler}-{Alpha158}, {qlib.contrib.data.handler}-{Alpha158vwap}, {qlib.contrib.data.handler}-{Alpha360}, {qlib.contrib.data.handler}-{Alpha360vwap}, {qlib.data.dataset.loader}-{QlibDataLoader}
DataHandler: {qlib.contrib.data.handler}-{Alpha158}, {qlib.contrib.data.handler}-{Alpha360},
Model: {qlib.contrib.model.catboost_model}-{CatBoostModel}, {qlib.contrib.model.double_ensemble}-{DoubleEnsembleModel}, {qlib.contrib.model.gbdt}-{LGBModel}, {qlib.contrib.model.highfreq_gdbt_model}-{HFLGBModel}, {qlib.contrib.model.linear}-{LinearModel}, {qlib.contrib.model.pytorch_adarnn}-{AdaRNNModel}, {qlib.contrib.model.pytorch_add}-{ADD}, {qlib.contrib.model.pytorch_alstm_ts}-{ALSTM}, {qlib.contrib.model.pytorch_alstm}-{ALSTM}, {qlib.contrib.model.pytorch_gats}-{GATs}, {qlib.contrib.model.pytorch_gats_ts}-{GATs}, {qlib.contrib.model.pytorch_gru}-{GRU}, {qlib.contrib.model.pytorch_gru_ts}-{GRU}, {qlib.contrib.model.pytorch_hist}-{HIST}, {qlib.contrib.model.pytorch_igmtf}-{IGMTF}, {qlib.contrib.model.pytorch_localformer}-{LocalformerModel}, {qlib.contrib.model.pytorch_localformer_ts}-{LocalformerModel}, {qlib.contrib.model.pytorch_lstm}-{LSTM}, {qlib.contrib.model.pytorch_lstm_ts}-{LSTM}, {qlib.contrib.model.pytorch_nn}-{DNNModelPytorch}, {qlib.contrib.model.pytorch_sfm}-{SFM}, {qlib.contrib.model.pytorch_tabnet}-{TabnetModel}, {qlib.contrib.model.pytorch_tcn_ts}-{TCN}, {qlib.contrib.model.pytorch_tcn}-{TCN}, {qlib.contrib.model.pytorch_tcts.}-{TCTS}, {qlib.contrib.model.pytorch_tra}-{TRA}, {qlib.contrib.model.pytorch_transformer}-{TransformerModel}, {qlib.contrib.model.pytorch_transformer_ts}-{TransformerModel}, {qlib.contrib.model.xgboost}-{XGBModel}
Record: {qlib.workflow.record_temp}-{SignalRecord}, {qlib.workflow.record_temp}-{SigAnaRecord},
Strategy: {qlib.contrib.strategy}-{TopkDropoutStrategy}, {qlib.contrib.strategy}-{WeightStrategyBase}, {qlib.contrib.strategy}-{EnhancedIndexingStrategy}, {qlib.contrib.strategy}-{TWAPStrategy}, {qlib.contrib.strategy}-{SBBStrategyBase}, {qlib.contrib.strategy}-{SBBStrategyEMA}, {qlib.contrib.strategy}-{SoftTopkStrategy}
Caution, {qlib.contrib.data.dataset}-{MTSDatasetH} only works with {qlib.contrib.model.pytorch_tra}-{TRA}, so do not use any of them alone!
The list will be called as "predefined classes" in the following prompts.
{qlib.contrib.data.handler}-{Alpha158vwap} and {qlib.contrib.data.handler}-{Alpha360vwap} is not necessary, try to use the pure version of datahandler.
For each component, you first point out whether to use default module in Qlib or implement the new module (Default or Personized). Default module means picking one of the predefined classes to meet the user's requirement. Personized module means new python class implemented and called from config file. The new class should always inherit from one of the class in the predefined classes.
If choose Default, provide the predefined class after the choice, otherwise, provide the predefined class your code plans to inherit from. the format of predefined class should follow the previous format. Backtest module has no predefined class so you don't need to provide.
@ -120,7 +178,9 @@ SLPlanTask_system : |-
Target: maximize the excess return
Deliverables: a daily quantitative investment strategy in US stock market. A model will be included in the strategy.
Thinking directions:
Business level: Model
Business level:
Controller: no custom controller
Target module: Model
Algorithm level: supervised learning
Details:
Because the user wants to maximize the excess return and more complicated model often extracts more deep pattern from the data. So try a more complicated DNN model to get more excess return than a simple linear model
@ -151,7 +211,8 @@ SLPlanTask_user : |-
Target: {{ target }}
Deliverables: {{ deliverables }}
Thinking directions:
Business level: {{ business_level }}
Business level:
{{ business_level }}
Algorithm level: {{ algorithm_level }}
Details:
{{ thinking_detail }}
@ -163,8 +224,9 @@ ConfigSearchTask_system : |-
The predifined module in Qlib can be listed as:
Dataset: {qlib.data.dataset}-{DatasetH}, {qlib.contrib.data.dataset}-{MTSDatasetH}
DataHandler: {qlib.contrib.data.handler}-{Alpha158}, {qlib.contrib.data.handler}-{Alpha158vwap}, {qlib.contrib.data.handler}-{Alpha360}, {qlib.contrib.data.handler}-{Alpha360vwap}, {qlib.data.dataset.loader}-{QlibDataLoader}
DataHandler: {qlib.contrib.data.handler}-{Alpha158}, {qlib.contrib.data.handler}-{Alpha360}
Model: {qlib.contrib.model.catboost_model}-{CatBoostModel}, {qlib.contrib.model.double_ensemble}-{DoubleEnsembleModel}, {qlib.contrib.model.gbdt}-{LGBModel}, {qlib.contrib.model.highfreq_gdbt_model}-{HFLGBModel}, {qlib.contrib.model.linear}-{LinearModel}, {qlib.contrib.model.pytorch_adarnn}-{AdaRNNModel}, {qlib.contrib.model.pytorch_add}-{ADD}, {qlib.contrib.model.pytorch_alstm_ts}-{ALSTM}, {qlib.contrib.model.pytorch_alstm}-{ALSTM}, {qlib.contrib.model.pytorch_gats}-{GATs}, {qlib.contrib.model.pytorch_gats_ts}-{GATs}, {qlib.contrib.model.pytorch_gru}-{GRU}, {qlib.contrib.model.pytorch_gru_ts}-{GRU}, {qlib.contrib.model.pytorch_hist}-{HIST}, {qlib.contrib.model.pytorch_igmtf}-{IGMTF}, {qlib.contrib.model.pytorch_localformer}-{LocalformerModel}, {qlib.contrib.model.pytorch_localformer_ts}-{LocalformerModel}, {qlib.contrib.model.pytorch_lstm}-{LSTM}, {qlib.contrib.model.pytorch_lstm_ts}-{LSTM}, {qlib.contrib.model.pytorch_nn}-{DNNModelPytorch}, {qlib.contrib.model.pytorch_sfm}-{SFM}, {qlib.contrib.model.pytorch_tabnet}-{TabnetModel}, {qlib.contrib.model.pytorch_tcn_ts}-{TCN}, {qlib.contrib.model.pytorch_tcn}-{TCN}, {qlib.contrib.model.pytorch_tcts.}-{TCTS}, {qlib.contrib.model.pytorch_tra}-{TRA}, {qlib.contrib.model.pytorch_transformer}-{TransformerModel}, {qlib.contrib.model.pytorch_transformer_ts}-{TransformerModel}, {qlib.contrib.model.xgboost}-{XGBModel}
Caution, {qlib.contrib.data.dataset}-{MTSDatasetH} only works with {qlib.contrib.model.pytorch_tra}-{TRA}, so do not use any of them alone!
The user will design several experiments and provide the dataset, datahandler and model option.
@ -204,7 +266,7 @@ AnalysisTask_system : |-
one analyser, separate them by ","
AnalysisTask_user : |-
{{user_prompt}},
{{user_intention}},
The analyzers you select should separate by ",", such as: "HFAnalyzer", "SignalAnalyzer"
CMDTask_system : |-
@ -231,11 +293,9 @@ CMDTask_user : |-
HyperparameterFinetuneActionTask_system : |-
You are an Quant investment Research and development assistant whose job is to help the user to modify the config file of Qlib.
The user will provide a statement of their research requirement, and some thoughts about the research topic. The thoughts includes the target of the research, the deliverables of the target and the thinking direction. The thinking direction includes two levels: algorithm level decides the workflow and algorithm level related thoughts and business level decides the main controller or which of the crucial components in Qlib (Dataset, DataHandler, Model, Record, Strategy, Backtest) is targeted in this research round.
The user has designed several experiments and provided the description of each experiment. About each experiment, user has prepared a default templated config.
Then the user will design several experiments and provide the description of each experiment. About each experiment, user has prepared a default templated config.
Your jib is to check the default config whether we need to change some part of the config.
Your job is to check two default config whether we need to change some part of the config. The config needs to be changed only when: 1. The config didn't follow the user's description of the experiment. 2. Two config didn't match each other on the non focused part of the user description. The detail of the config like hyperparameter choosing is not important and you only need to keep them the same on both configs.
User will provide two experiments, and both config files are included in user's input. Config file is showed in yaml format. You only focus on the difference of the config and try not to modify if modification is not very necessary.
@ -243,19 +303,12 @@ HyperparameterFinetuneActionTask_system : |-
Caution: Modifying the config to use some meta controller in training process like rolling or DDGDA is impossible. If the user wants to use these meta controller, please DON'T change the config but mention it in the reason!
If you want to modify the config, please reply the changed whole config instead of some part.
If you want to modify the config, please reply the whole changed config instead of some part. Otherwise, you don't need to reply any yaml based config.
You should answer exactly the same format as example.
Example input:
User intention: build an US stock market daily portfolio in quantitative investment and maximize the excess return.
Target: maximize the excess return
Deliverables: a daily quantitative investment strategy in US stock market. A model will be included in the strategy.
Thinking directions:
Business level: Model
Algorithm level: supervised learning
Details:
Because the user wants to maximize the excess return and more complicated model often extracts more deep pattern from the data. So try a more complicated DNN model to get more excess return than a simple linear model
Experiments:
1. Train a simple linear model ({qlib.contrib.model.linear}-{LinearModel}) on the dataset ({qlib.data.dataset}-{DatasetH}) and use the Alpha158 ({qlib.contrib.data.handler}-{Alpha158}) data handler. Use the default hyperparameters.
2. Train a deep LSTM model ({qlib.contrib.model.pytorch_lstm}-{LSTM}) on the dataset ({qlib.data.dataset}-{DatasetH}) and use the Alpha158 ({qlib.contrib.data.handler}-{Alpha158}) data handler. Use the default hyperparameters.
@ -265,6 +318,7 @@ HyperparameterFinetuneActionTask_system : |-
qlib_init:
provider_uri: "~/.qlib/qlib_data/cn_data"
region: cn
experiment_name: finCo
market: &market csi300
benchmark: &benchmark SH000300
data_handler_config: &data_handler_config
@ -291,9 +345,7 @@ HyperparameterFinetuneActionTask_system : |-
class: TopkDropoutStrategy
module_path: qlib.contrib.strategy
kwargs:
signal:
- <MODEL>
- <DATASET>
signal: <PRED>
topk: 50
n_drop: 5
backtest:
@ -312,7 +364,8 @@ HyperparameterFinetuneActionTask_system : |-
class: LinearModel
module_path: qlib.contrib.model.linear
kwargs:
estimator: ols
estimator: ridge
alpha: 0.05
dataset:
class: DatasetH
module_path: qlib.data.dataset
@ -340,7 +393,6 @@ HyperparameterFinetuneActionTask_system : |-
module_path: qlib.workflow.record_temp
kwargs:
config: *port_analysis_config
```
Config 2:
```yaml
@ -348,6 +400,7 @@ HyperparameterFinetuneActionTask_system : |-
qlib_init:
provider_uri: "~/.qlib/qlib_data/cn_data"
region: cn
experiment_name: finCo
market: &market csi300
benchmark: &benchmark SH000300
data_handler_config: &data_handler_config
@ -357,13 +410,6 @@ HyperparameterFinetuneActionTask_system : |-
fit_end_time: 2014-12-31
instruments: *market
infer_processors:
- class: FilterCol
kwargs:
fields_group: feature
col_list: ["RESI5", "WVMA5", "RSQR5", "KLEN", "RSQR10", "CORR5", "CORD5", "CORR10",
"ROC60", "RESI10", "VSTD5", "RSQR60", "CORR60", "WVMA60", "STD5",
"RSQR20", "CORD60", "CORD10", "CORR20", "KLOW"
]
- class: RobustZScoreNorm
kwargs:
fields_group: feature
@ -376,15 +422,99 @@ HyperparameterFinetuneActionTask_system : |-
- class: CSRankNorm
kwargs:
fields_group: label
label: ["Ref($close, -2) / Ref($close, -1) - 1"]
port_analysis_config: &port_analysis_config
strategy:
class: TopkDropoutStrategy
module_path: qlib.contrib.strategy
kwargs:
signal:
- <MODEL>
- <DATASET>
signal: <PRED>
topk: 50
n_drop: 5
backtest:
start_time: 2017-01-01
end_time: 2020-08-01
account: 100000000
benchmark: *benchmark
exchange_kwargs:
limit_threshold: 0.095
deal_price: close
open_cost: 0.0005
close_cost: 0.0015
min_cost: 5
task:
model:
class: LinearModel
module_path: qlib.contrib.model.linear
kwargs:
estimator: ridge
alpha: 0.05
dataset:
class: DatasetH
module_path: qlib.data.dataset
kwargs:
handler:
class: Alpha158
module_path: qlib.contrib.data.handler
kwargs: *data_handler_config
segments:
train: [2008-01-01, 2014-12-31]
valid: [2015-01-01, 2016-12-31]
test: [2017-01-01, 2020-08-01]
record:
- class: SignalRecord
module_path: qlib.workflow.record_temp
kwargs:
model: <MODEL>
dataset: <DATASET>
- class: SigAnaRecord
module_path: qlib.workflow.record_temp
kwargs:
ana_long_short: True
ann_scaler: 252
- class: PortAnaRecord
module_path: qlib.workflow.record_temp
kwargs:
config: *port_analysis_config
```
Example output:
Experiment 1: Rolling: False, DDGDA: False.
Reason: No need to change the config. Because user wants to use default hyperparameter of linear model.
Experiment 2: Rolling: False, DDGDA: False.
Reason: Need to modify the model part of the config while the other parts remain unchanged. Because user wants to use default hyperparameter of LSTM model while control the variable of the other parts.
Modified Config:
```yaml
qlib_init:
provider_uri: "~/.qlib/qlib_data/cn_data"
region: cn
experiment_name: finCo
market: &market csi300
benchmark: &benchmark SH000300
data_handler_config: &data_handler_config
start_time: 2008-01-01
end_time: 2020-08-01
fit_start_time: 2008-01-01
fit_end_time: 2014-12-31
instruments: *market
infer_processors:
- class: RobustZScoreNorm
kwargs:
fields_group: feature
clip_outlier: true
- class: Fillna
kwargs:
fields_group: feature
learn_processors:
- class: DropnaLabel
- class: CSRankNorm
kwargs:
fields_group: label
port_analysis_config: &port_analysis_config
strategy:
class: TopkDropoutStrategy
module_path: qlib.contrib.strategy
kwargs:
signal: <PRED>
topk: 50
n_drop: 5
backtest:
@ -416,7 +546,7 @@ HyperparameterFinetuneActionTask_system : |-
n_jobs: 20
GPU: 0
dataset:
class: TSDatasetH
class: DatasetH
module_path: qlib.data.dataset
kwargs:
handler:
@ -427,7 +557,6 @@ HyperparameterFinetuneActionTask_system : |-
train: [2008-01-01, 2014-12-31]
valid: [2015-01-01, 2016-12-31]
test: [2017-01-01, 2020-08-01]
step_len: 20
record:
- class: SignalRecord
module_path: qlib.workflow.record_temp
@ -437,7 +566,7 @@ HyperparameterFinetuneActionTask_system : |-
- class: SigAnaRecord
module_path: qlib.workflow.record_temp
kwargs:
ana_long_short: False
ana_long_short: True
ann_scaler: 252
- class: PortAnaRecord
module_path: qlib.workflow.record_temp
@ -445,28 +574,15 @@ HyperparameterFinetuneActionTask_system : |-
config: *port_analysis_config
```
Example output:
Experiment 1: Rolling: False, DDGDA: False.
Reason: No need to change the config. Because user wants to use default hyperparameter of linear model.
Experiment 2: Rolling: False, DDGDA: False.
Reason: No need to change the config. Because user wants to use default hyperparameter of LSTM model.
HyperparameterFinetuneActionTask_user : |-
Caution: Modifying the config to use some meta controller in training process like rolling or DDGDA is impossible. If the user wants to use these meta controller, please DON'T change the config but mention it in the reason!
User intention: {{ user_intention }}
Target: {{ target }}
Deliverables: {{ deliverables }}
Thinking directions:
Business level: {{ business_level }}
Algorithm level: {{ algorithm_level }}
Details:
{{ thinking_detail }}
Experiments:
{{experiments}}
{% for index, config in template_configs %}
Config {{index}}:
```yaml{{ config }}
```
Config {{index}}:
```yaml
{{ config }}
```
{% endfor %}
HyperparameterActionTask_system : |-
@ -475,10 +591,12 @@ HyperparameterActionTask_system : |-
The predefined class in the target Qlib module can be listed in format of {module_path}-{class name}:
{% if target_module == "Dataset" %}
Dataset: {qlib.data.dataset}-{DatasetH}, {qlib.contrib.data.dataset}-{MTSDatasetH}
Caution, {qlib.contrib.data.dataset}-{MTSDatasetH} only works with {qlib.contrib.model.pytorch_tra}-{TRA}, so do not use any of them alone!
{% elif target_module == "DataHandler" %}
DataHandler: {qlib.contrib.data.handler}-{Alpha158}, {qlib.contrib.data.handler}-{Alpha158vwap}, {qlib.contrib.data.handler}-{Alpha360}, {qlib.contrib.data.handler}-{Alpha360vwap}, {qlib.data.dataset.loader}-{QlibDataLoader}
DataHandler: {qlib.contrib.data.handler}-{Alpha158}, {qlib.contrib.data.handler}-{Alpha360}
{% elif target_module == "Model" %}
Model: {qlib.contrib.model.catboost_model}-{CatBoostModel}, {qlib.contrib.model.double_ensemble}-{DoubleEnsembleModel}, {qlib.contrib.model.gbdt}-{LGBModel}, {qlib.contrib.model.highfreq_gdbt_model}-{HFLGBModel}, {qlib.contrib.model.linear}-{LinearModel}, {qlib.contrib.model.pytorch_adarnn}-{AdaRNNModel}, {qlib.contrib.model.pytorch_add}-{ADD}, {qlib.contrib.model.pytorch_alstm_ts}-{ALSTM}, {qlib.contrib.model.pytorch_alstm}-{ALSTM}, {qlib.contrib.model.pytorch_gats}-{GATs}, {qlib.contrib.model.pytorch_gats_ts}-{GATs}, {qlib.contrib.model.pytorch_gru}-{GRU}, {qlib.contrib.model.pytorch_gru_ts}-{GRU}, {qlib.contrib.model.pytorch_hist}-{HIST}, {qlib.contrib.model.pytorch_igmtf}-{IGMTF}, {qlib.contrib.model.pytorch_localformer}-{LocalformerModel}, {qlib.contrib.model.pytorch_localformer_ts}-{LocalformerModel}, {qlib.contrib.model.pytorch_lstm}-{LSTM}, {qlib.contrib.model.pytorch_lstm_ts}-{LSTM}, {qlib.contrib.model.pytorch_nn}-{DNNModelPytorch}, {qlib.contrib.model.pytorch_sfm}-{SFM}, {qlib.contrib.model.pytorch_tabnet}-{TabnetModel}, {qlib.contrib.model.pytorch_tcn_ts}-{TCN}, {qlib.contrib.model.pytorch_tcn}-{TCN}, {qlib.contrib.model.pytorch_tcts.}-{TCTS}, {qlib.contrib.model.pytorch_tra}-{TRA}, {qlib.contrib.model.pytorch_transformer}-{TransformerModel}, {qlib.contrib.model.pytorch_transformer_ts}-{TransformerModel}, {qlib.contrib.model.xgboost}-{XGBModel}
Caution, {qlib.contrib.data.dataset}-{MTSDatasetH} only works with {qlib.contrib.model.pytorch_tra}-{TRA}, so do not use any of them alone!
{% elif target_module == "Record" %}
Record: {qlib.workflow.record_temp}-{SignalRecord}, {qlib.workflow.record_temp}-{SigAnaRecord},
{% elif target_module == "Strategy" %}
@ -697,10 +815,12 @@ ConfigActionTask_system: |-
The predefined class in the target Qlib module can be listed in format of {module_path}-{class name}:
{% if target_module == "Dataset" %}
Dataset: {qlib.data.dataset}-{DatasetH}, {qlib.contrib.data.dataset}-{MTSDatasetH}
Caution, {qlib.contrib.data.dataset}-{MTSDatasetH} only works with {qlib.contrib.model.pytorch_tra}-{TRA}, so do not use any of them alone!
{% elif target_module == "DataHandler" %}
DataHandler: {qlib.contrib.data.handler}-{Alpha158}, {qlib.contrib.data.handler}-{Alpha158vwap}, {qlib.contrib.data.handler}-{Alpha360}, {qlib.contrib.data.handler}-{Alpha360vwap}, {qlib.data.dataset.loader}-{QlibDataLoader}
DataHandler: {qlib.contrib.data.handler}-{Alpha158}, {qlib.contrib.data.handler}-{Alpha360}
{% elif target_module == "Model" %}
Model: {qlib.contrib.model.catboost_model}-{CatBoostModel}, {qlib.contrib.model.double_ensemble}-{DoubleEnsembleModel}, {qlib.contrib.model.gbdt}-{LGBModel}, {qlib.contrib.model.highfreq_gdbt_model}-{HFLGBModel}, {qlib.contrib.model.linear}-{LinearModel}, {qlib.contrib.model.pytorch_adarnn}-{AdaRNNModel}, {qlib.contrib.model.pytorch_add}-{ADD}, {qlib.contrib.model.pytorch_alstm_ts}-{ALSTM}, {qlib.contrib.model.pytorch_alstm}-{ALSTM}, {qlib.contrib.model.pytorch_gats}-{GATs}, {qlib.contrib.model.pytorch_gats_ts}-{GATs}, {qlib.contrib.model.pytorch_gru}-{GRU}, {qlib.contrib.model.pytorch_gru_ts}-{GRU}, {qlib.contrib.model.pytorch_hist}-{HIST}, {qlib.contrib.model.pytorch_igmtf}-{IGMTF}, {qlib.contrib.model.pytorch_localformer}-{LocalformerModel}, {qlib.contrib.model.pytorch_localformer_ts}-{LocalformerModel}, {qlib.contrib.model.pytorch_lstm}-{LSTM}, {qlib.contrib.model.pytorch_lstm_ts}-{LSTM}, {qlib.contrib.model.pytorch_nn}-{DNNModelPytorch}, {qlib.contrib.model.pytorch_sfm}-{SFM}, {qlib.contrib.model.pytorch_tabnet}-{TabnetModel}, {qlib.contrib.model.pytorch_tcn_ts}-{TCN}, {qlib.contrib.model.pytorch_tcn}-{TCN}, {qlib.contrib.model.pytorch_tcts.}-{TCTS}, {qlib.contrib.model.pytorch_tra}-{TRA}, {qlib.contrib.model.pytorch_transformer}-{TransformerModel}, {qlib.contrib.model.pytorch_transformer_ts}-{TransformerModel}, {qlib.contrib.model.xgboost}-{XGBModel}
Caution, {qlib.contrib.data.dataset}-{MTSDatasetH} only works with {qlib.contrib.model.pytorch_tra}-{TRA}, so do not use any of them alone!
{% elif target_module == "Record" %}
Record: {qlib.workflow.record_temp}-{SignalRecord}, {qlib.workflow.record_temp}-{SigAnaRecord},
{% elif target_module == "Strategy" %}
@ -984,7 +1104,7 @@ SummarizeTask_system : |-
SummarizeTask_user : |-
Here is my information: '{{information}}'
My intention is: {{user_prompt}}. Please provide me with a summary and recommendation based on my intention and the information I have provided. There are some figures which absolute path are: {{figure_path}}, You must display these images in markdown using the appropriate image format.
My intention is: {{user_intention}}. Please provide me with a summary and recommendation based on my intention and the information I have provided. There are some figures which absolute path are: {{figure_path}}, You must display these images in markdown using the appropriate image format.
SummarizeTask_context_system : |-
Your purpose is to find out the important information offered by user. You can just show the data provided by user in markdown format.
@ -1007,7 +1127,7 @@ LearnManager_user : |-
Brief of this workflow is:{{brief}}\n
Tasks I have run are: {{task_finished}},\n
{{task}}'s system prompt is: {{system}}.\n
User's intention is: {{user_prompt}}.
User's intention is: {{user_intention}}.
If you have no idea how to optimize the system prompt, you can just return the original system prompt.
you will adjust {{task}}'s system prompt to:

Просмотреть файл

@ -9,7 +9,7 @@ import re
import subprocess
import platform
import inspect
from jinja2 import Template
import qlib
from qlib.finco.llm import APIBackend
from qlib.finco.tpl import get_tpl_path
@ -136,8 +136,8 @@ class WorkflowTask(Task):
def execute(self) -> List[Task]:
"""make the choice which main workflow (RL, SL) will be used"""
user_prompt = self._context_manager.get_context("user_prompt")
prompt_workflow_selection = self.user.render(user_prompt=user_prompt)
user_intention = self._context_manager.get_context("user_intention")
prompt_workflow_selection = self.user.render(user_intention=user_intention)
response = APIBackend().build_messages_and_create_chat_completion(
prompt_workflow_selection, self.system.render()
)
@ -166,27 +166,65 @@ class WorkflowTask(Task):
class PlanTask(Task):
pass
class IdeaTask(PlanTask):
def __init__(self) -> None:
super().__init__()
def execute(self):
user_intention = self._context_manager.get_context("user_intention")
practice_knowledge = KnowledgeBase().query(knowledge_type=KnowledgeBase.KT_PRACTICE, content=user_intention)
finance_knowledge = KnowledgeBase().query(knowledge_type=KnowledgeBase.KT_FINANCE, content=user_intention)
system_prompt = self.system.render()
former_messages = []
for knowlege in [practice_knowledge, finance_knowledge]:
if knowlege != '':
knowlege_type = "practice" if knowlege is practice_knowledge else "finance"
user_prompt = ""
user_prompt += f"following lists the {knowlege_type} knowledge:\n"
user_prompt += f"{knowlege}\n"
response = APIBackend().build_messages_and_create_chat_completion(
user_prompt, system_prompt, former_messages=former_messages
)
assert "ok" in response.lower(), "The response is not ok"
self.save_chat_history_to_context_manager(
user_prompt, response, system_prompt
)
former_messages = self._context_manager.get_context("chat_history")[self.__class__.__name__]['None'][1:]
user_prompt = f"""\nResearch intention:\n{user_intention}"""
response = APIBackend().build_messages_and_create_chat_completion(
user_prompt, system_prompt, former_messages=former_messages
)
re_search_pattern = f"Target: (.*)Deliverables:(.*)Thinking directions:(.*)Business level:(.*)Algorithm level:(.*)Details:(.*)"
re_search_res = re.search(re_search_pattern, response, re.S)
assert re_search_res is not None, "The response is not ok"
assert len(re_search_res.groups()) == 6, "The response is not ok"
self._context_manager.set_context("target", re_search_res.group(1).strip(" \n"))
self._context_manager.set_context("deliverable", re_search_res.group(2).strip(" \n"))
self._context_manager.set_context("business_level", re_search_res.group(4).strip(" \n"))
self._context_manager.set_context("algorithm_level", re_search_res.group(5).strip(" \n"))
self._context_manager.set_context("thinking_detail", re_search_res.group(6).strip(" \n"))
return [HighLevelPlanTask()]
class HighLevelPlanTask(PlanTask):
def __init__(self) -> None:
super().__init__()
def execute(self):
self._context_manager.set_context("target", "minimizing the maximum drawdown")
self._context_manager.set_context(
"deliverable",
"a daily quantitative investment strategy in A-share stock market. A model will be included in the strategy.",
)
self._context_manager.set_context(
"user_intention",
"build an A-share stock market daily portfolio in quantitative investment and minimize the maximum drawdown.",
)
self._context_manager.set_context("business_level", "Controller(e.g. Rolling retrain), Data")
self._context_manager.set_context("algorithm_level", "supervised learning")
self._context_manager.set_context(
"thinking_detail",
"We want to leverage more recent data than outdated data. So we have to compare with or without rolling training process of the model like a meta controller. When with a rolling training process, data will be different at each time.",
)
# self._context_manager.set_context("target", "minimizing the maximum drawdown")
# self._context_manager.set_context("deliverable", "a daily quantitative investment strategy in A-share stock market. A model will be included in the strategy.")
# self._context_manager.set_context("user_intention", "build an A-share stock market daily portfolio in quantitative investment and minimize the maximum drawdown.")
# self._context_manager.set_context("business_level", "Controller(e.g. Rolling retrain), Data")
# self._context_manager.set_context("algorithm_level", "supervised learning")
# self._context_manager.set_context("thinking_detail", "We want to leverage more recent data than outdated data. So we have to compare with or without rolling training process of the model like a meta controller. When with a rolling training process, data will be different at each time.")
target = self._context_manager.get_context("target")
deliverable = self._context_manager.get_context("deliverable")
@ -202,25 +240,15 @@ class HighLevelPlanTask(PlanTask):
assert thinking_detail is not None, "The thinking detail is not provided"
assert user_intention is not None, "The user intention is not provided"
practice_knowledge = KnowledgeBase().query(knowledge_type=KnowledgeBase.KT_PRACTICE, content=user_intention)
finance_knowledge = KnowledgeBase().query(knowledge_type=KnowledgeBase.KT_FINANCE, content=user_intention)
system_prompt = self.system.render()
user_prompt = self.user.render(
target=target,
deliverable=deliverable,
business_level=business_level,
algorithm_level=algorithm_level,
thinking_detail=thinking_detail,
practice_knowledge=practice_knowledge,
finance_knowledge=finance_knowledge,
user_intention=user_intention,
user_prompt = self.user.render(target=target, deliverable=deliverable, business_level=business_level,
algorithm_level=algorithm_level, thinking_detail=thinking_detail,
user_intention=user_intention)
response = APIBackend().build_messages_and_create_chat_completion(
user_prompt, system_prompt
)
response = APIBackend().build_messages_and_create_chat_completion(user_prompt, system_prompt)
response = APIBackend().build_messages_and_create_chat_completion(user_prompt, system_prompt)
self.save_chat_history_to_context_manager(user_prompt, response, system_prompt)
assert response is not None, "The response is None"
@ -261,7 +289,7 @@ class SLPlanTask(PlanTask):
user_intention = self._context_manager.get_context("user_intention")
experiments = self._context_manager.get_context("high_level_experiments")
experiment_count = max([i for i in range(10) if f"{i}." in experiments])
experiment_count = 2 # TODO fix
infrastructure_knowledge = KnowledgeBase().query(
knowledge_type=KnowledgeBase.KT_INFRASTRUCTURE, content=experiments
@ -281,8 +309,8 @@ class SLPlanTask(PlanTask):
former_messages = []
if self.replan:
user_prompt = f"your choice of predefined classes cannot be initialized.\nPlease rewrite the plan and answer with exact required format in system prompt and reply with no more explainations.\nThe error message: {self.error}. Please correct the former answer accordingly."
former_messages = self._context_manager.get_context("chat_history")[self.__class__.__name__]["None"][1:]
user_prompt = f"your choice of predefined classes cannot be initialized.\nPlease rewrite the plan and answer with exact required format in system prompt and reply with no more explainations.\nThe error message: {self.error}. Please correct the former with exactly same format accordingly and answer without any conversation and interaction.\nDon't forget the Difference section."
former_messages = self._context_manager.get_context("chat_history")[self.__class__.__name__]['None'][1:]
response = APIBackend().build_messages_and_create_chat_completion(
user_prompt, system_prompt, former_messages=former_messages
)
@ -404,18 +432,12 @@ class TrainTask(Task):
# todo: change global R.uri & experiment name
R.set_uri(Path(workspace).joinpath("mlruns").as_uri())
if not self._rolling:
command = ["qrun", str(workflow_path)]
command = f"qrun {str(workflow_path)}"
try:
# Run the command and capture the output
workspace = self._context_manager.get_context("workspace")
_ = subprocess.run(
command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=True,
text=True,
encoding="utf8",
cwd=str(workspace),
subprocess.run(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text=True, cwd=str(workspace), shell=True
)
exp = R.get_exp(experiment_name="finCo")
@ -454,21 +476,25 @@ class TrainTask(Task):
# Run the command and capture the output
workspace = self._context_manager.struct_context.workspace
subprocess.run(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True,
text=True, encoding="utf8", cwd=str(workspace)
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text=True, cwd=str(workspace), shell=True
)
# todo: dont manage record by id, experiment_id=2 doesnt contains metrics
exp = R.get_exp(experiment_id="3")
try:
exp = R.get_exp(experiment_id="3")
except qlib.utils.exceptions.ExpAlreadyExistError:
exp = R.get_exp(experiment_id="2")
else:
command = f"python -m qlib.contrib.rolling ddgda --conf_path {workflow_path} run"
# Run the command and capture the output
workspace = self._context_manager.struct_context.workspace
subprocess.run(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True,
encoding="utf8", text=True, cwd=str(workspace)
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text=True, cwd=str(workspace), shell=True
)
exp = R.get_exp(experiment_id="3")
try:
exp = R.get_exp(experiment_id="3")
except qlib.utils.exceptions.ExpAlreadyExistError:
exp = R.get_exp(experiment_id="2")
# first recorder is the latest
recorder = exp.list_recorders(rtype=exp.RT_L)[0]
@ -507,7 +533,9 @@ class AnalysisTask(Task):
self._context_manager.set_context(k, v)
def execute(self):
prompt = self.user.render(user_prompt=self._context_manager.get_context("user_prompt"))
prompt = self.user.render(
user_intention=self._context_manager.get_context("user_intention")
)
be = APIBackend()
be.debug_mode = False
@ -605,12 +633,13 @@ class ConfigSearchTask(ActionTask):
system_prompt = self.system.render(yaml_config_list=yaml_config_list)
user_prompt = self.user.render(experiments=experiments)
response = APIBackend().build_messages_and_create_chat_completion(user_prompt, system_prompt)
former_messages = []
response = APIBackend().build_messages_and_create_chat_completion(
user_prompt, self.system.render(), former_messages=former_messages
user_prompt, system_prompt, former_messages=former_messages
)
self.save_chat_history_to_context_manager(
user_prompt, response, system_prompt
)
self.save_chat_history_to_context_manager(user_prompt, response, self.system.render())
experiment_count = self._context_manager.get_context("experiment_count")
@ -625,15 +654,9 @@ class ConfigSearchTask(ActionTask):
CMDTask(f"make a directory in the {self._context_manager.get_context('workspace')}"),
]
for experiment_id in range(1, experiment_count + 1):
self._context_manager.set_context(
f"experiment_{experiment_id}_template_config", config_search_result.group(experiment_id).strip("\n")
)
config_location = self.conf_path / config_search_result.group(experiment_id)
return_task.append(
CMDTask(
f"copy file in {config_location} to {self._context_manager.get_context('workspace')} and rename to experiment_{experiment_id}.yaml"
)
)
self._context_manager.set_context(f"experiment_{experiment_id}_template_config", config_search_result.group(experiment_id).strip('\n'))
config_location = benchmarks_root_path / config_search_result.group(experiment_id).strip(" \n")
return_task.append(CMDTask(f"copy file in {config_location} to {self._context_manager.get_context('workspace')} and rename to experiment_{experiment_id}.yaml"))
return return_task
@ -1136,7 +1159,7 @@ class SummarizeTask(Task):
def execute(self) -> Any:
workspace = self._context_manager.get_context("workspace")
user_prompt = self._context_manager.get_context("user_prompt")
user_intention = self._context_manager.get_context("user_intention")
file_info = self.get_info_from_file(workspace)
context_info = self.get_info_from_context() # too long context make response unstable.
@ -1175,19 +1198,19 @@ class SummarizeTask(Task):
recorder.save_objects(context_summary=context_summary)
prompt_workflow_selection = self.summarize_metrics_user.render(
information=_get_value_from_info(info=record_info, k="metrics"), user_prompt=user_prompt
information=_get_value_from_info(info=record_info, k="metrics"), user_prompt=user_intention
)
metrics_response = be.build_messages_and_create_chat_completion(
user_prompt=prompt_workflow_selection, system_prompt=self.summarize_metrics_system.render()
)
KnowledgeBase().practice_knowledge.add([{"user_intention": user_prompt, "experiment_id": exp_id,
KnowledgeBase().practice_knowledge.add([{"user_intention": user_intention, "experiment_id": exp_id,
"workflow": workflow_yaml, "reason": reason,
"experiment_metrics": metrics_response}])
prompt_workflow_selection = self.user.render(
information=file_info + KnowledgeBase().practice_knowledge.knowledge[-2:],
figure_path=figure_path, user_prompt=user_prompt
figure_path=figure_path, user_prompt=user_intention
)
response = be.build_messages_and_create_chat_completion(
user_prompt=prompt_workflow_selection, system_prompt=self.system.render()

Просмотреть файл

@ -3,7 +3,8 @@ import shutil
from typing import List
from pathlib import Path
from qlib.finco.task import HighLevelPlanTask, SummarizeTask, AnalysisTask
from qlib.finco.task import IdeaTask, SummarizeTask
from qlib.finco.prompt_template import PromptTemplate, Template
from qlib.finco.log import FinCoLog, LogColors
from qlib.finco.llm import APIBackend
@ -53,6 +54,7 @@ class WorkflowManager:
self.prompt_template = PromptTemplate()
self.context = WorkflowContextManager(workspace=self._workspace)
self.context.set_context("workspace", self._workspace)
self.default_user_prompt = "build an A-share stock market daily portfolio in quantitative investment and minimize the maximum drawdown."
def _confirm_and_rm(self):
@ -109,13 +111,13 @@ class WorkflowManager:
# NOTE: default user prompt might be changed in the future and exposed to the user
if prompt is None:
self.set_context("user_prompt", self.default_user_prompt)
self.set_context("user_intention", self.default_user_prompt)
else:
self.set_context("user_prompt", prompt)
self.logger.info(f"user_prompt: {self.get_context().get_context('user_prompt')}", title="Start")
self.set_context("user_intention", prompt)
self.logger.info(f"user_intention: {self.get_context().get_context('user_intention')}", title="Start")
# NOTE: list may not be enough for general task list
task_list = [HighLevelPlanTask(), AnalysisTask(), SummarizeTask()]
task_list = [IdeaTask(), SummarizeTask()]
task_finished = []
while len(task_list):
task_list_info = [str(task) for task in task_list]
@ -176,7 +178,7 @@ class LearnManager:
# one task maybe run several times in workflow
task_finished = _drop_duplicate_task(self.wm.context.get_context("task_finished"))
user_prompt = self.wm.context.get_context("user_prompt")
user_intention = self.wm.context.get_context("user_intention")
summary = self.wm.context.get_context("summary")
[topic.summarize(self.knowledge_base.practice_knowledge.knowledge[-2:]) for topic in self.topics]
@ -188,9 +190,7 @@ class LearnManager:
summary=summary,
brief=knowledge_of_topics,
task_finished=[str(t) for t in task_finished],
task=task.__class__.__name__,
system=task.system.render(),
user_prompt=user_prompt,
task=task.__class__.__name__, system=task.system.render(), user_intention=user_intention
)
response = APIBackend().build_messages_and_create_chat_completion(