From 25fb571a0f47ebd697d36cd393b830398accf786 Mon Sep 17 00:00:00 2001
From: WinstonLiyt <104308117+WinstonLiyt@users.noreply.github.com>
Date: Thu, 25 Jul 2024 16:18:00 +0800
Subject: [PATCH] A draft of the "Quick Start" section for your README. Enable
logging of backtesting in Qlib and store rich-text descriptions in Trace.
Support one-step debugging for factor extraction. (#105)
- A draft of the "Quick Start" section for your README.
- Enable logging of backtesting in Qlib and store rich-text descriptions in Trace.
- Support one-step debugging for factor extraction.
---
README.md | 69 +++++++++++++---
docs/installation.rst | 24 ++++++
docs/scenarios_and_quickstart.rst | 82 ++++++++++++++++++-
rdagent/app/qlib_rd_loop/conf.py | 52 ++++++------
rdagent/app/qlib_rd_loop/factor_w_sc.py | 38 +++++++++
rdagent/app/qlib_rd_loop/model_w_sc.py | 68 ++-------------
rdagent/components/workflow/rd_loop.py | 3 +-
.../qlib/experiment/factor_experiment.py | 4 +
.../factor_template/read_exp_res.py | 3 +
.../scenarios/qlib/experiment/workspace.py | 2 +-
rdagent/scenarios/qlib/prompts.yaml | 11 ++-
11 files changed, 252 insertions(+), 104 deletions(-)
create mode 100644 rdagent/app/qlib_rd_loop/factor_w_sc.py
diff --git a/README.md b/README.md
index ab8196cc..595fc7bd 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,12 @@
TODO: Add badges.
-# News
+# ๐ฐ News
| ๐๏ธNews | ๐Description |
| -- | ------ |
| First release | RDAgent are release on Github |
-# Introduction
+# ๐ Introduction

@@ -31,15 +31,62 @@ We have a quick ๐ฅdemo for one use case of RDAgent.
# โกQuick start
You can try our demo by running the following command:
-```bash
-# TODO:
-# prepare environment
-# installation
-# App entrance
-```
+### ๐ Create a Conda Environment
+- Create a new conda environment with Python (3.10 and 3.11 are well tested in our CI):
+ ```sh
+ conda create -n rdagent python=3.10
+ ```
+- Activate the environment:
+ ```sh
+ conda activate rdagent
+ ```
+
+### ๐ ๏ธ Run Make Files
+TODO: `pip install rdagent` in the future.
+
+- **Navigate to the directory containing the MakeFile** and set up the development environment:
+ ```sh
+ make dev
+ ```
+
+### ๐ฆ Install Pytorch
+TODO: use docker in quick start intead.
+
+- Install Pytorch and related libraries:
+ ```sh
+ pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
+ pip3 install torch_geometric
+ ```
+
+### โ๏ธ Environment Configuration
+- Place the `.env` file in the same directory as the `.env.example` file.
+ - TOOD: please refer to ... for the detailed explanation of the `.env`
+ - TODO: simplify `.env.example` only keep OpenAI or Azure Azure OpenAI
+- Export each variable in the `.env` file:
+ ```sh
+ export $(grep -v '^#' .env | xargs)
+ ```
+### ๐ Run the Application
+TODO: run the front-page demo.
The [๐ฅdemo]() is implemented by the above commands.
+- Run the factor extraction and implementation application based on financial reports:
+ ```sh
+ python rdagent/app/qlib_rd_loop/factor_from_report_sh.py
+ ```
+
+- Run the self-loop factor extraction and implementation application:
+ ```sh
+ python rdagent/app/qlib_rd_loop/factor.py
+ ```
+
+- Run the self-loop model extraction and implementation application:
+ ```sh
+ python rdagent/app/qlib_rd_loop/model.py
+ ```
+
+
# Scenarios
We have applied RD-Agent to multiple valuable data-driven industrial scenarios..
@@ -60,9 +107,9 @@ Here is our supported scenarios
| Scenario/Target | Model Implementation | Data Building |
| -- | -- | -- |
-| ๐นFinance | Iteratively Proposing Ideas & Evolving | - Auto reports reading & implementation
- Iteratively Proposing Ideas & Evolving |
-| ๐ฉบMedical | Iteratively Proposing Ideas & Evolving | - |
-| General | Auto paper reading & implementation | - |
+| ๐น Finance | Iteratively Proposing Ideas & Evolving | - Auto reports reading & implementation
- Iteratively Proposing Ideas & Evolving |
+| ๐ฉบ Medical | Iteratively Proposing Ideas & Evolving | - |
+| ๐ญ General | Auto paper reading & implementation | - |
Different scenarios vary in entrance and configuration. Please check the detailed setup tutorial in the scenarios documents.
diff --git a/docs/installation.rst b/docs/installation.rst
index 90a3f1a0..b4852be3 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -13,3 +13,27 @@ Configuration
=============
Quick configuration
+
+
+
+
+Azure OpenAI
+------------
+
+
+
+USE_AZURE_TOKEN_PROVIDER
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+### โ๏ธ Azure Configuration
+- Install Azure CLI:
+ ```sh
+ curl -L https://aka.ms/InstallAzureCli | bash
+ ```
+- Log in to Azure:
+ ```sh
+ az login --use-device-code
+ ```
+
+- `exit` and re-login to your environment (this step may not be necessary).
+
diff --git a/docs/scenarios_and_quickstart.rst b/docs/scenarios_and_quickstart.rst
index cdc613b6..e264cb24 100644
--- a/docs/scenarios_and_quickstart.rst
+++ b/docs/scenarios_and_quickstart.rst
@@ -5,29 +5,107 @@ Scenarios and Quick Start
Scenario lists
=========================
-TODO: Copy the content in the README.md
+.. list-table::
+ :header-rows: 1
+ * - Scenario/Target
+ - Model Implementation
+ - Data Building
+ * - ๐น Finance
+ - Iteratively Proposing Ideas & Evolving
+ - Auto reports reading & implementation
+ Iteratively Proposing Ideas & Evolving
+ * - ๐ฉบ Medical
+ - Iteratively Proposing Ideas & Evolving
+ -
+ * - ๐ญ General
+ - Auto paper reading & implementation
+ -
Scnarios' demo & quick start
=========================
Scen1
-----
+๐ค Knowledge-Based Hypothesis Generation and Iteration
Scen1 Intro
~~~~~~~~~~~
+In this scenario, our model autonomously generates and tests hypotheses using a knowledge base. The process involves:
+
+- **๐ Hypothesis Generation**: The model proposes new hypotheses.
+- **๐ Factor Creation**: Write and define new factors.
+- **โ
Factor Validation**: Validate the factors quantitatively.
+- **๐ Backtesting with Qlib**:
+
+ - **Dataset**: CSI300
+ - **Model**: LGBModel
+ - **Factors**: Alpha158 +
+ - **Data Split**:
+
+ - **Train**: 2008-01-01 to 2014-12-31
+ - **Valid**: 2015-01-01 to 2016-12-31
+ - **Test**: 2017-01-01 to 2020-08-01
+- **๐ Feedback Analysis**: Analyze backtest results.
+- **๐ง Hypothesis Refinement**: Refine hypotheses based on feedback and repeat.
Scen1 Demo
~~~~~~~~~~
+.. TODO
Scen1 Quick Start
~~~~~~~~~~~~~~~~~
+To quickly start the factor extraction process, run the following command in your terminal within the 'rdagent' virtual environment:
+.. code-block:: sh
+ python rdagent/app/qlib_rd_loop/factor.py
Usage of modules
-================
+~~~~~~~~~~~~~~~~~
TODO: Show some examples:
+
+Scen2:
+-----
+๐ Research Report-Based Factor Extraction
+
+Scen2 Intro
+~~~~~~~~~~~
+In this scenario, factors and hypotheses are extracted from research reports. The process includes:
+
+- **๐ Factor Extraction**: Extract relevant factors from research reports.
+- **๐ Factor Creation**: Define these extracted factors.
+- **โ
Factor Validation**: Validate the extracted factors.
+- **๐ Backtesting with Qlib**:
+
+ - **Dataset**: CSI300
+ - **Model**: LGBModel
+ - **Factors**: Alpha158 +
+ - **Data Split**:
+
+ - **Train**: 2008-01-01 to 2014-12-31
+ - **Valid**: 2015-01-01 to 2016-12-31
+ - **Test**: 2017-01-01 to 2020-08-01
+- **๐ Feedback Analysis**: Analyze backtest results.
+- **๐ง Hypothesis Refinement**: Refine hypotheses based on feedback and continue the cycle.
+
+Scen2 Demo
+~~~~~~~~~~
+.. TODO
+
+Scen2 Quick Start
+~~~~~~~~~~~~~~~~~
+
+To quickly start the factor extraction process, run the following command in your terminal within the 'rdagent' virtual environment:
+
+.. code-block:: sh
+
+ python rdagent/app/qlib_rd_loop/factor_from_report_sh.py
+
+
+Usage of modules
+~~~~~~~~~~~~~~~~~
+TODO: Show some examples:
\ No newline at end of file
diff --git a/rdagent/app/qlib_rd_loop/conf.py b/rdagent/app/qlib_rd_loop/conf.py
index 60d63dbb..cf618866 100644
--- a/rdagent/app/qlib_rd_loop/conf.py
+++ b/rdagent/app/qlib_rd_loop/conf.py
@@ -1,39 +1,43 @@
-from pathlib import Path
-
-from pydantic_settings import BaseSettings
+from rdagent.components.workflow.conf import BasePropSetting
-class PropSetting(BaseSettings):
+class ModelBasePropSetting(BasePropSetting):
class Config:
- env_prefix = "QLIB_" # Use MODEL_CODER_ as prefix for environment variables
+ env_prefix = "QLIB_MODEL_" # Use MODEL_CODER_ as prefix for environment variables
protected_namespaces = () # Add 'model_' to the protected namespaces
- factor_scen: str = "rdagent.scenarios.qlib.experiment.factor_experiment.QlibFactorScenario"
- factor_hypothesis_gen: str = "rdagent.scenarios.qlib.proposal.factor_proposal.QlibFactorHypothesisGen"
- factor_hypothesis2experiment: str = (
- "rdagent.scenarios.qlib.proposal.factor_proposal.QlibFactorHypothesis2Experiment"
- )
- factor_coder: str = "rdagent.scenarios.qlib.developer.factor_coder.QlibFactorCoSTEER"
- factor_runner: str = "rdagent.scenarios.qlib.developer.factor_runner.QlibFactorRunner"
- factor_summarizer: str = "rdagent.scenarios.qlib.developer.feedback.QlibFactorHypothesisExperiment2Feedback"
-
- # TODO: model part is not finished yet
- model_scen: str = "rdagent.scenarios.qlib.experiment.model_experiment.QlibModelScenario"
- model_hypothesis_gen: str = "rdagent.scenarios.qlib.proposal.model_proposal.QlibModelHypothesisGen"
- model_hypothesis2experiment: str = "rdagent.scenarios.qlib.proposal.model_proposal.QlibModelHypothesis2Experiment"
- model_coder: str = "rdagent.scenarios.qlib.developer.model_coder.QlibModelCoSTEER"
- model_runner: str = "rdagent.scenarios.qlib.developer.model_runner.QlibModelRunner"
- model_summarizer: str = "rdagent.scenarios.qlib.developer.feedback.QlibModelHypothesisExperiment2Feedback"
+ scen: str = "rdagent.scenarios.qlib.experiment.model_experiment.QlibModelScenario"
+ hypothesis_gen: str = "rdagent.scenarios.qlib.proposal.model_proposal.QlibModelHypothesisGen"
+ hypothesis2experiment: str = "rdagent.scenarios.qlib.proposal.model_proposal.QlibModelHypothesis2Experiment"
+ coder: str = "rdagent.scenarios.qlib.developer.model_coder.QlibModelCoSTEER"
+ runner: str = "rdagent.scenarios.qlib.developer.model_runner.QlibModelRunner"
+ summarizer: str = "rdagent.scenarios.qlib.developer.feedback.QlibModelHypothesisExperiment2Feedback"
evolving_n: int = 10
- py_bin: str = "/usr/bin/python"
- local_qlib_folder: Path = Path("/home/rdagent/qlib")
+class FactorBasePropSetting(BasePropSetting):
+ class Config:
+ env_prefix = "QLIB_FACTOR_" # Use MODEL_CODER_ as prefix for environment variables
+ protected_namespaces = () # Add 'model_' to the protected namespaces
+
+ # 1) override base settings
+ # TODO: model part is not finished yet
+ scen: str = "rdagent.scenarios.qlib.experiment.factor_experiment.QlibFactorScenario"
+ hypothesis_gen: str = "rdagent.scenarios.qlib.proposal.factor_proposal.QlibFactorHypothesisGen"
+ hypothesis2experiment: str = "rdagent.scenarios.qlib.proposal.factor_proposal.QlibFactorHypothesis2Experiment"
+ coder: str = "rdagent.scenarios.qlib.developer.factor_coder.QlibFactorCoSTEER"
+ runner: str = "rdagent.scenarios.qlib.developer.factor_runner.QlibFactorRunner"
+ summarizer: str = "rdagent.scenarios.qlib.developer.feedback.QlibFactorHypothesisExperiment2Feedback"
+
+ evolving_n: int = 10
+
+ # 2) sub task specific:
origin_report_path: str = "data/report_origin"
local_report_path: str = "data/report"
report_result_json_file_path: str = "git_ignore_folder/res_dict.json"
progress_file_path: str = "git_ignore_folder/progress.pkl"
-PROP_SETTING = PropSetting()
+FACTOR_PROP_SETTING = FactorBasePropSetting()
+MODEL_PROP_SETTING = ModelBasePropSetting()
diff --git a/rdagent/app/qlib_rd_loop/factor_w_sc.py b/rdagent/app/qlib_rd_loop/factor_w_sc.py
new file mode 100644
index 00000000..1e6f8220
--- /dev/null
+++ b/rdagent/app/qlib_rd_loop/factor_w_sc.py
@@ -0,0 +1,38 @@
+"""
+Factor workflow with session control
+"""
+
+import fire
+
+from rdagent.app.qlib_rd_loop.conf import FACTOR_PROP_SETTING
+from rdagent.components.workflow.rd_loop import RDLoop
+from rdagent.core.exception import FactorEmptyError
+
+
+class FactorRDLoop(RDLoop):
+ skip_loop_error = (FactorEmptyError,)
+
+
+def main(path=None, step_n=None):
+ """
+ You can continue running session by
+
+ .. code-block:: python
+
+ dotenv run -- python rdagent/app/qlib_rd_loop/factor_w_sc.py $LOG_PATH/__session__/1/0_propose --step_n 1 # `step_n` is a optional paramter
+
+ """
+ if path is None:
+ model_loop = FactorRDLoop(FACTOR_PROP_SETTING)
+ else:
+ model_loop = FactorRDLoop.load(path)
+ model_loop.run(step_n=step_n)
+
+
+if __name__ == "__main__":
+ fire.Fire(main)
+
+
+
+if __name__ == "__main__":
+ fire.Fire(main)
diff --git a/rdagent/app/qlib_rd_loop/model_w_sc.py b/rdagent/app/qlib_rd_loop/model_w_sc.py
index c5fca4c3..59e89b67 100644
--- a/rdagent/app/qlib_rd_loop/model_w_sc.py
+++ b/rdagent/app/qlib_rd_loop/model_w_sc.py
@@ -1,70 +1,16 @@
"""
Model workflow with session control
-It is from `rdagent/app/qlib_rd_loop/model.py` and try to replace `rdagent/app/qlib_rd_loop/RDAgent.py`
"""
import fire
-from typing import Any
-from rdagent.app.qlib_rd_loop.conf import PROP_SETTING
-from rdagent.core.developer import Developer
+
+from rdagent.app.qlib_rd_loop.conf import MODEL_PROP_SETTING
+from rdagent.components.workflow.rd_loop import RDLoop
from rdagent.core.exception import ModelEmptyError
-from rdagent.core.proposal import (
- Hypothesis2Experiment,
- HypothesisExperiment2Feedback,
- HypothesisGen,
- Trace,
-)
-from rdagent.core.scenario import Scenario
-from rdagent.core.utils import import_class
-from rdagent.log import rdagent_logger as logger
-from rdagent.utils.workflow import LoopMeta, LoopBase
-class ModelLoop(LoopBase, metaclass=LoopMeta):
- # TODO: supporting customized loop control like catching `ModelEmptyError`
-
- def __init__(self):
- scen: Scenario = import_class(PROP_SETTING.model_scen)()
-
- self.hypothesis_gen: HypothesisGen = import_class(PROP_SETTING.model_hypothesis_gen)(scen)
-
- self.hypothesis2experiment: Hypothesis2Experiment = import_class(PROP_SETTING.model_hypothesis2experiment)()
-
- self.qlib_model_coder: Developer = import_class(PROP_SETTING.model_coder)(scen)
- self.qlib_model_runner: Developer = import_class(PROP_SETTING.model_runner)(scen)
-
- self.qlib_model_summarizer: HypothesisExperiment2Feedback = import_class(PROP_SETTING.model_summarizer)(scen)
- self.trace = Trace(scen=scen)
- super().__init__()
-
- def propose(self, prev_out: dict[str, Any]):
- with logger.tag("r"): # research
- hypothesis = self.hypothesis_gen.gen(self.trace)
- logger.log_object(hypothesis, tag="hypothesis generation")
- return hypothesis
-
- def exp_gen(self, prev_out: dict[str, Any]):
- with logger.tag("r"): # research
- exp = self.hypothesis2experiment.convert(prev_out["propose"], self.trace)
- logger.log_object(exp.sub_tasks, tag="experiment generation")
- return exp
-
- def coding(self, prev_out: dict[str, Any]):
- with logger.tag("d"): # develop
- exp = self.qlib_model_coder.develop(prev_out["exp_gen"])
- logger.log_object(exp.sub_workspace_list, tag="model coder result")
- return exp
-
- def running(self, prev_out: dict[str, Any]):
- with logger.tag("ef"): # evaluate and feedback
- exp = self.qlib_model_runner.develop(prev_out["coding"])
- logger.log_object(exp, tag="model runner result")
- return exp
-
- def feedback(self, prev_out: dict[str, Any]):
- feedback = self.qlib_model_summarizer.generate_feedback(prev_out["running"], prev_out["propose"], self.trace)
- logger.log_object(feedback, tag="feedback")
- self.trace.hist.append((prev_out["propose"],prev_out["running"] , feedback))
+class ModelRDLoop(RDLoop):
+ skip_loop_error = (ModelEmptyError,)
def main(path=None, step_n=None):
@@ -77,9 +23,9 @@ def main(path=None, step_n=None):
"""
if path is None:
- model_loop = ModelLoop()
+ model_loop = ModelRDLoop(MODEL_PROP_SETTING)
else:
- model_loop = ModelLoop.load(path)
+ model_loop = ModelRDLoop.load(path)
model_loop.run(step_n=step_n)
diff --git a/rdagent/components/workflow/rd_loop.py b/rdagent/components/workflow/rd_loop.py
index 69a73d5d..d1a40017 100644
--- a/rdagent/components/workflow/rd_loop.py
+++ b/rdagent/components/workflow/rd_loop.py
@@ -60,5 +60,6 @@ class RDLoop(LoopBase, metaclass=LoopMeta):
def feedback(self, prev_out: dict[str, Any]):
feedback = self.summarizer.generate_feedback(prev_out["running"], prev_out["propose"], self.trace)
- logger.log_object(feedback, tag="feedback")
+ with logger.tag("ef"): # evaluate and feedback
+ logger.log_object(feedback, tag="feedback")
self.trace.hist.append((prev_out["propose"],prev_out["running"] , feedback))
diff --git a/rdagent/scenarios/qlib/experiment/factor_experiment.py b/rdagent/scenarios/qlib/experiment/factor_experiment.py
index b4821eb4..09e166d5 100644
--- a/rdagent/scenarios/qlib/experiment/factor_experiment.py
+++ b/rdagent/scenarios/qlib/experiment/factor_experiment.py
@@ -39,6 +39,10 @@ class QlibFactorScenario(Scenario):
@property
def simulator(self) -> str:
return prompt_dict["qlib_factor_simulator"]
+
+ @property
+ def rich_style_description(self)->str:
+ return "Below is QlibFactor Evolving Automatic R&D Demo."
def get_scenario_all_desc(self) -> str:
return f"""Background of the scenario:
diff --git a/rdagent/scenarios/qlib/experiment/factor_template/read_exp_res.py b/rdagent/scenarios/qlib/experiment/factor_template/read_exp_res.py
index 19930248..d08e3b4c 100644
--- a/rdagent/scenarios/qlib/experiment/factor_template/read_exp_res.py
+++ b/rdagent/scenarios/qlib/experiment/factor_template/read_exp_res.py
@@ -43,3 +43,6 @@ else:
metrics.to_csv(output_path)
print(f"Output has been saved to {output_path}")
+
+ ret_data_frame = latest_recorder.load_object("portfolio_analysis/report_normal_1day.pkl")
+ ret_data_frame.to_pickle("ret.pkl")
\ No newline at end of file
diff --git a/rdagent/scenarios/qlib/experiment/workspace.py b/rdagent/scenarios/qlib/experiment/workspace.py
index 00871440..f3e16e11 100644
--- a/rdagent/scenarios/qlib/experiment/workspace.py
+++ b/rdagent/scenarios/qlib/experiment/workspace.py
@@ -31,7 +31,7 @@ class QlibFBWorkspace(FBWorkspace):
)
ret_df = pd.read_pickle(self.workspace_path / "ret.pkl")
- logger.log_object(ret_df, tag="returns") # TODO: tag
+ logger.log_object(ret_df, tag="Quantitative Backtesting Chart")
csv_path = self.workspace_path / "qlib_res.csv"
diff --git a/rdagent/scenarios/qlib/prompts.yaml b/rdagent/scenarios/qlib/prompts.yaml
index 19814df6..139ebd57 100644
--- a/rdagent/scenarios/qlib/prompts.yaml
+++ b/rdagent/scenarios/qlib/prompts.yaml
@@ -59,7 +59,7 @@ factor_hypothesis_specification: |-
- "Filter stocks by market capitalization before calculating the factors."
factor_hypothesis_specification: |-
- Additional Specifications:
+ Specifications:
- Hypotheses should grow and evolve based on the previous hypothesis. If there is no previous hypothesis, start with something simple.
- Gradually build upon previous hypotheses and feedback.
- Ensure that the hypothesis focuses on the creation and selection of factors in quantitative finance.
@@ -94,7 +94,7 @@ factor_hypothesis_specification: |-
- "Investigate the impact of an earnings surprise factor calculated from recent earnings announcements."
- "Develop a composite factor integrating ESG (Environmental, Social, Governance) scores with traditional financial metrics."
- Detailed Workflow:
+ Detailed Workflow: (These are just examples for the format, do not be constrained by these examples)
1. Initial Hypothesis:
- Begin with a simple factor, such as "Include a momentum factor based on the last 12 months' returns."
@@ -110,8 +110,11 @@ factor_hypothesis_specification: |-
5. Advanced Hypotheses:
- Explore sophisticated combinations or new types of factors, e.g., "Develop a composite factor integrating ESG scores with traditional financial metrics."
- Remember: If a hypothesis achieves the desired results, start a new direction while preserving the effective factors from previous hypotheses. New evaluations should combine the newly proposed factors with previously successful factors that surpassed SOTA.
-
+ Important Note:
+ - If a hypothesis achieves the desired results, start a new direction while preserving the effective factors from previous hypotheses.
+ - New evaluations should combine the newly proposed factors with previously successful factors that surpassed SOTA.
+ - If the previous hypothesis factor exceeds SOTA, you can write another factor in the same direction, otherwise, explore new directions.
+ - The final maintained SOTA is the continuous accumulation of factors that surpass each iteration.
factor_experiment_output_format: |-
The output should follow JSON format. The schema is as follows: