1
0
mirror of https://github.com/microsoft/qlib.git synced 2026-07-20 02:37:38 +08:00

Compare commits

..

13 Commits

Author SHA1 Message Date
you-n-g
42cda0a3b1 chore(main): release 0.9.8 2025-11-13 11:52:38 +08:00
Linlang
2b41782f0c fix(gbdt): correct dtrain assignment in finetune() to use Dataset instead of tuple (#2049) 2025-11-13 11:50:43 +08:00
Ronny Pfannschmidt
ac3fe9476f chore(build): rely on integrated setuptools_scm instead of manual call (#2032)
* dont manually call setuptools_scm - its integrated

setuptools_scm automatically set the version attribute - manually setting it wrong

* fix(docs): set fallback version for setuptools-scm to fix autodoc import errors on Read the Docs

---------

Co-authored-by: SunsetWolf <Lv.Linlang@hotmail.com>
2025-11-10 18:25:04 +08:00
Linlang
66c36226aa fix(macd): remove extra division by close in DEA calculation to ensure dimension consistency (#2046) 2025-11-06 21:49:15 +08:00
shauryaMi12
bb7ab1cf14 docs: fix spelling mistake: exmaple to example (#2033)
Co-authored-by: Linlang <Lv.Linlang@hotmail.com>
2025-10-17 13:20:16 +08:00
shauryaMi12
3dc5a7d299 fix: typo in integration documentation: 'userd' -> 'used' (#2034)
* Fix typo in integration docs: 'userd' -> 'used'

* fix: pylint error in CI

---------

Co-authored-by: Linlang <Lv.Linlang@hotmail.com>
2025-10-16 11:07:55 +08:00
Kei YAMAZAKI
7d66e4b788 docs: update Docker run command in README.md to specify the correct image name (#2010) 2025-09-15 17:09:36 +08:00
Linlang
213eb6c2cd fix: the bug when auto_mount=True (#2009)
* fix: the bug when auto_mount=True

* fix: the bug when auto_mount=True
2025-09-11 20:05:17 +08:00
Linlang
94d138ec23 chore: align collect_info.py with pyproject.toml (#1997)
* chore: Align collect_info.py with pyproject.toml

* delete version info

* chore: align collect_info.py with pyproject.toml
2025-09-03 19:29:18 +08:00
Linlang
f26b341736 fix: spelling errors (#1996)
Co-authored-by: XYUU <xyuu@xyuu.net>
2025-09-01 16:11:41 +08:00
Linlang
136b2ddf9a fix: download orderbook data error (#1990) 2025-08-19 17:44:27 +08:00
Alaa Kaddour
7095e755fa fix: replace deprecated pandas fillna(method=) with ffill()/bfill() (#1987)
* fix: replace deprecated pandas fillna(method=) with ffill()/bfill()

  Replace deprecated fillna(method="ffill"/"bfill") calls with modern
  pandas ffill() and bfill() methods to fix FutureWarnings in pandas 2.x.

  Also includes black formatting fixes for compliance.

  This addresses the pandas deprecation warnings portion of issue #1981.
  Other issues (date parsing, type conversion, timezone handling) will be
  addressed in separate commits.

  Fixes:
  - Yahoo collector: 2 instances in calc_change() and adjusted_price()
  - BaoStock collector: 1 instance in calc_change()
  - Core utils: resam.py fillna operations
  - Backtest: profit_attribution.py stock data processing
  - High-freq ops: FFillNan and BFillNan operators
  - Position analysis: parse_position.py weight processing

  Partially addresses GitHub issue #1981

* lint with black

* lint with black

* limit minimum version of pandas

* limit minimum version of pandas

---------

Co-authored-by: Linlang <Lv.Linlang@hotmail.com>
2025-08-19 16:00:29 +08:00
Linlang
2d05a705e3 ci: auto release (#1985)
* ci: auto release

* fix: bug getting version in qlib/__init__.py

* fix: bug getting version in setup.py

* fix: bug getting version in qlib/__init__.py

* fix: make the code in CI more complete

* fix: specify the root directory in the get_verison method

* fix: parameter error

* update: optimize code && add comments
2025-08-18 17:28:00 +08:00
32 changed files with 285 additions and 210 deletions

21
.commitlintrc.js Normal file
View File

@@ -0,0 +1,21 @@
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
// Configuration Format: [level, applicability, value]
// level: Error level, usually expressed as a number:
// 0 - disable rule
// 1 - Warning (does not prevent commits)
// 2 - Error (will block the commit)
// applicability: the conditions under which the rule applies, commonly used values:
// “always” - always apply the rule
// “never” - never apply the rule
// value: the specific value of the rule, e.g. a maximum length of 100.
// Refs: https://commitlint.js.org/reference/rules-configuration.html
"header-max-length": [2, "always", 100],
"type-enum": [
2,
"always",
["build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test", "Release-As"]
]
}
};

View File

@@ -1,3 +1,16 @@
<!--- Thank you for submitting a Pull Request! In order to make our work smoother. -->
<!--- please make sure your Pull Request meets the following requirements: -->
<!--- 1. Provide a general summary of your changes in the Title above; -->
<!--- 2. Add appropriate prefixes to titles, such as `build:`, `chore:`, `ci:`, `docs:`, `feat:`, `fix:`, `perf:`, `refactor:`, `revert:`, `style:`, `test:`(Ref: https://www.conventionalcommits.org/). -->
<!--- Category: -->
<!--- Patch Updates: `fix:` -->
<!--- Example: fix(auth): correct login validation issue -->
<!--- minor update (introduces new functionality): `feat` -->
<!--- Example: feature(parser): add ability to parse arrays -->
<!--- major update(destructive update): Include BREAKING CHANGE in the commit message footer, or add `! ` in the commit footer to indicate that there is a destructive update. -->
<!--- Example: feat(auth)! : remove support for old authentication method -->
<!--- Other updates: `build:`, `chore:`, `ci:`, `docs:`, `perf:`, `refactor:`, `revert:`, `style:`, `test:`. -->
<!--- Provide a general summary of your changes in the Title above --> <!--- Provide a general summary of your changes in the Title above -->
## Description ## Description

6
.github/labeler.yml vendored
View File

@@ -1,6 +0,0 @@
documentation:
- 'docs/**/*'
- '**/*.md'
waiting for triage:
- any: ['**/*', '!docs/**/*', '!**/*.md']

View File

@@ -1,14 +0,0 @@
name: "Add label automatically"
on:
- pull_request_target
jobs:
triage:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v4
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

35
.github/workflows/lint_title.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Lint pull request title
on:
pull_request:
types:
- opened
- synchronize
- reopened
- edited
concurrency:
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
lint-title:
runs-on: ubuntu-latest
steps:
# This step is necessary because the lint title uses the .commitlintrc.js file in the project root directory.
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '16'
- name: Install commitlint
run: npm install --save-dev @commitlint/{config-conventional,cli}
- name: Validate PR Title with commitlint
env:
BODY: ${{ github.event.pull_request.title }}
run: |
echo "$BODY" | npx commitlint --config .commitlintrc.js

View File

@@ -1,65 +0,0 @@
# This workflows will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
name: Upload Python Package
on:
release:
types: [published]
jobs:
deploy_with_bdist_wheel:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest, macos-13, macos-latest]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
exclude:
- os: macos-13
python-version: "3.11"
- os: macos-13
python-version: "3.12"
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
make dev
- name: Build wheel on ${{ matrix.os }}
run: |
make build
- name: Upload to PyPi
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: |
twine check dist/*.whl
twine upload dist/*.whl --verbose
deploy_with_manylinux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Build wheel on Linux
uses: RalfG/python-wheels-manylinux-build@v0.7.1-manylinux2014_x86_64
with:
python-versions: 'cp38-cp38 cp39-cp39 cp310-cp310 cp311-cp311 cp312-cp312'
build-requirements: 'numpy cython'
- name: Install dependencies
run: |
python -m pip install twine
- name: Upload to PyPi
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: |
twine check dist/pyqlib-*-manylinux*.whl
twine upload dist/pyqlib-*-manylinux*.whl --verbose

View File

@@ -1,22 +0,0 @@
name: Release Drafter
on:
push:
# branches to consider in the event; optional, defaults to all
branches:
- main
permissions:
contents: read
jobs:
update_release_draft:
permissions:
contents: write
pull-requests: read
runs-on: ubuntu-latest
steps:
# Drafts your next Release notes as Pull Requests are merged into "master"
- uses: release-drafter/release-drafter@v5.11.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

107
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,107 @@
name: Release
on:
push:
branches:
- main
permissions:
contents: read
jobs:
release:
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release_please.outputs.release_created }}
steps:
- name: Release please
id: release_please
uses: googleapis/release-please-action@v4
with:
token: ${{ secrets.PAT }}
release-type: simple
deploy_with_manylinux:
needs: release
permissions:
contents: write
pull-requests: read
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
if: needs.release.outputs.release_created == 'true'
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
if: needs.release.outputs.release_created == 'true'
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Build wheel on Linux
if: needs.release.outputs.release_created == 'true'
uses: RalfG/python-wheels-manylinux-build@v0.7.1-manylinux2014_x86_64
with:
python-versions: 'cp38-cp38 cp39-cp39 cp310-cp310 cp311-cp311 cp312-cp312'
build-requirements: 'numpy cython'
- name: Install dependencies
if: needs.release.outputs.release_created == 'true'
run: |
python -m pip install twine
- name: Upload to PyPi
if: needs.release.outputs.release_created == 'true'
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.TESTPYPI }}
run: |
twine check dist/pyqlib-*-manylinux*.whl
twine upload --repository-url https://test.pypi.org/legacy/ dist/pyqlib-*-manylinux*.whl --verbose
deploy_with_bdist_wheel:
needs: release
runs-on: ${{ matrix.os }}
strategy:
matrix:
# After testing, the whl files of pyqlib built by macos-14 and macos-15 in python environments of 3.8, 3.9, 3.10, 3.11, 3.12,
# the filenames are exactly duplicated, which will result in the duplicated whl files not being able to be uploaded to pypi,
# so we chose to just keep the latest macos-latest. macos-latest currently points to macos-15.
# Also, macos-13 will stop being supported on 2025-11-14.
# Refs: https://github.blog/changelog/2025-07-11-upcoming-changes-to-macos-hosted-runners-macos-latest-migration-and-xcode-support-policy-updates/
os: [windows-latest, macos-latest]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
if: needs.release.outputs.release_created == 'true'
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
if: needs.release.outputs.release_created == 'true'
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
if: needs.release.outputs.release_created == 'true'
run: |
make dev
- name: Build wheel on ${{ matrix.os }}
if: needs.release.outputs.release_created == 'true'
run: |
make build
- name: Upload to PyPi
if: needs.release.outputs.release_created == 'true'
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.TESTPYPI }}
run: |
twine check dist/*.whl
twine upload --repository-url https://test.pypi.org/legacy/ dist/*.whl --verbose

View File

@@ -21,7 +21,9 @@ jobs:
steps: steps:
- name: Test qlib from pip - name: Test qlib from pip
uses: actions/checkout@v3 uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@@ -32,19 +34,9 @@ jobs:
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
# Will cancel this step when the next qlib version is released. The current qlib version is: 0.9.6
- name: Installing pywinpt for windows
if: ${{ matrix.os == 'windows-latest' }}
run: |
python -m pip install pywinpty --only-binary=:all:
# # joblib was released on 2025-05-04 with version 1.5.0, in which _backend_args was removed and replaced by _backend_kwargs.
# This change caused the application to fail, so the version of joblib is restricted here.
# This restriction will be removed in the next release. The current qlib version is: 0.9.6
- name: Qlib installation test - name: Qlib installation test
run: | run: |
python -m pip install pyqlib python -m pip install pyqlib
python -m pip install "joblib<=1.4.2"
- name: Install Lightgbm for MacOS - name: Install Lightgbm for MacOS
if: ${{ matrix.os == 'macos-14' || matrix.os == 'macos-15' }} if: ${{ matrix.os == 'macos-14' || matrix.os == 'macos-15' }}
@@ -53,12 +45,10 @@ jobs:
brew install libomp || brew reinstall libomp brew install libomp || brew reinstall libomp
python -m pip install --no-binary=:all: lightgbm python -m pip install --no-binary=:all: lightgbm
# When the new version is released it should be changed to:
# python -m qlib.cli.data qlib_data --target_dir ~/.qlib/qlib_data/cn_data --region cn
- name: Downloads dependencies data - name: Downloads dependencies data
run: | run: |
cd .. cd ..
python -m qlib.run.get_data qlib_data --target_dir ~/.qlib/qlib_data/cn_data --region cn python -m qlib.cli.data qlib_data --target_dir ~/.qlib/qlib_data/cn_data --region cn
cd qlib cd qlib
- name: Test workflow by config - name: Test workflow by config

View File

@@ -22,7 +22,9 @@ jobs:
steps: steps:
- name: Test qlib from source - name: Test qlib from source
uses: actions/checkout@v3 uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4 uses: actions/setup-python@v4

View File

@@ -22,7 +22,9 @@ jobs:
steps: steps:
- name: Test qlib from source slow - name: Test qlib from source slow
uses: actions/checkout@v3 uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@@ -37,8 +39,6 @@ jobs:
run: | run: |
python scripts/get_data.py qlib_data --name qlib_data_simple --target_dir ~/.qlib/qlib_data/cn_data --interval 1d --region cn python scripts/get_data.py qlib_data --name qlib_data_simple --target_dir ~/.qlib/qlib_data/cn_data --interval 1d --region cn
# install.sh file contents from: https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh
# brew_install.sh file contents from: https://raw.githubusercontent.com/Microsoft/qlib/main/.github/brew_install.sh
- name: Install Lightgbm for MacOS - name: Install Lightgbm for MacOS
if: ${{ matrix.os == 'macos-14' || matrix.os == 'macos-15' }} if: ${{ matrix.os == 'macos-14' || matrix.os == 'macos-15' }}
run: | run: |

14
CHANGELOG.md Normal file
View File

@@ -0,0 +1,14 @@
# Changelog
## [0.9.8](https://github.com/microsoft/qlib/compare/v0.9.7...v0.9.8) (2025-11-13)
### Bug Fixes
* download orderbook data error ([#1990](https://github.com/microsoft/qlib/issues/1990)) ([136b2dd](https://github.com/microsoft/qlib/commit/136b2ddf9a16e4106d62b8d1336a56273a8abef0))
* **gbdt:** correct dtrain assignment in finetune() to use Dataset instead of tuple ([#2049](https://github.com/microsoft/qlib/issues/2049)) ([2b41782](https://github.com/microsoft/qlib/commit/2b41782f0cfb81e8cc065f2915b215758a7838ef))
* **macd:** remove extra division by close in DEA calculation to ensure dimension consistency ([#2046](https://github.com/microsoft/qlib/issues/2046)) ([66c3622](https://github.com/microsoft/qlib/commit/66c36226aafceabe497e5967f67921e5d3c9d497))
* replace deprecated pandas fillna(method=) with ffill()/bfill() ([#1987](https://github.com/microsoft/qlib/issues/1987)) ([7095e75](https://github.com/microsoft/qlib/commit/7095e755fa57e011f0483d24b45fc5bd5a4deaf8))
* spelling errors ([#1996](https://github.com/microsoft/qlib/issues/1996)) ([f26b341](https://github.com/microsoft/qlib/commit/f26b3417363410531dbbb39e425bce6cf05528a1))
* the bug when auto_mount=True ([#2009](https://github.com/microsoft/qlib/issues/2009)) ([213eb6c](https://github.com/microsoft/qlib/commit/213eb6c2cd12342b6ec98f21300217e1659f3d58))
* typo in integration documentation: 'userd' -&gt; 'used' ([#2034](https://github.com/microsoft/qlib/issues/2034)) ([3dc5a7d](https://github.com/microsoft/qlib/commit/3dc5a7d299074f0fa45a4b7bb50ab446a8824a32))

View File

@@ -113,7 +113,7 @@ dev: prerequisite all
# Check lint with black. # Check lint with black.
black: black:
black . -l 120 --check --diff black . -l 120 --check --diff --exclude qlib/_version.py
# Check code folder with pylint. # Check code folder with pylint.
# TODO: These problems we will solve in the future. Important among them are: W0221, W0223, W0237, E1102 # TODO: These problems we will solve in the future. Important among them are: W0221, W0223, W0237, E1102

View File

@@ -324,7 +324,7 @@ We recommend users to prepare their own data if they have a high-quality dataset
``` ```
2. Start a new Docker container 2. Start a new Docker container
```bash ```bash
docker run -it --name <container name> -v <Mounted local directory>:/app qlib_image_stable docker run -it --name <container name> -v <Mounted local directory>:/app pyqlib/qlib_image_stable:stable
``` ```
3. At this point you are in the docker environment and can run the qlib scripts. An example: 3. At this point you are in the docker environment and can run the qlib scripts. An example:
```bash ```bash

View File

@@ -42,7 +42,7 @@ Example
.. math:: .. math::
DEA = \frac{EMA(DIF, 9)}{CLOSE} DEA = EMA(DIF, 9)
Users can use ``Data Handler`` to build formulaic alphas `MACD` in qlib: Users can use ``Data Handler`` to build formulaic alphas `MACD` in qlib:
@@ -51,7 +51,7 @@ Users can use ``Data Handler`` to build formulaic alphas `MACD` in qlib:
.. code-block:: python .. code-block:: python
>> from qlib.data.dataset.loader import QlibDataLoader >> from qlib.data.dataset.loader import QlibDataLoader
>> MACD_EXP = '(EMA($close, 12) - EMA($close, 26))/$close - EMA((EMA($close, 12) - EMA($close, 26))/$close, 9)/$close' >> MACD_EXP = '2 * ((EMA($close, 12) - EMA($close, 26))/$close - EMA((EMA($close, 12) - EMA($close, 26))/$close, 9))'
>> fields = [MACD_EXP] # MACD >> fields = [MACD_EXP] # MACD
>> names = ['MACD'] >> names = ['MACD']
>> labels = ['Ref($close, -2)/Ref($close, -1) - 1'] # label >> labels = ['Ref($close, -2)/Ref($close, -1) - 1'] # label
@@ -66,17 +66,17 @@ Users can use ``Data Handler`` to build formulaic alphas `MACD` in qlib:
feature label feature label
MACD LABEL MACD LABEL
datetime instrument datetime instrument
2010-01-04 SH600000 -0.011547 -0.019672 2010-01-04 SH600000 0.008781 -0.019672
SH600004 0.002745 -0.014721 SH600004 0.006699 -0.014721
SH600006 0.010133 0.002911 SH600006 0.005714 0.002911
SH600008 -0.001113 0.009818 SH600008 0.000798 0.009818
SH600009 0.025878 -0.017758 SH600009 0.017015 -0.017758
... ... ... ... ... ...
2017-12-29 SZ300124 0.007306 -0.005074 2017-12-29 SZ300124 0.015071 -0.005074
SZ300136 -0.013492 0.056352 SZ300136 -0.015466 0.056352
SZ300144 -0.000966 0.011853 SZ300144 0.013082 0.011853
SZ300251 0.004383 0.021739 SZ300251 -0.001026 0.021739
SZ300315 -0.030557 0.012455 SZ300315 -0.007559 0.012455
Reference Reference
========= =========

View File

@@ -129,7 +129,7 @@ For example, it looks quite long and complicated:
But using string is not the only way to implement the expression. You can also implement expression by code. But using string is not the only way to implement the expression. You can also implement expression by code.
Here is an exmaple which does the same thing as above examples. Here is an example which does the same thing as above examples.
.. code-block:: python .. code-block:: python

View File

@@ -71,7 +71,7 @@ The Custom models need to inherit `qlib.model.base.Model <../reference/api.html#
) )
- Override the `predict` method - Override the `predict` method
- The parameters must include the parameter `dataset`, which will be userd to get the test dataset. - The parameters must include the parameter `dataset`, which will be used to get the test dataset.
- Return the `prediction score`. - Return the `prediction score`.
- Please refer to `Model API <../reference/api.html#module-qlib.model.base>`_ for the parameter types of the fit method. - Please refer to `Model API <../reference/api.html#module-qlib.model.base>`_ for the parameter types of the fit method.
- Code Example: In the following example, users need to use `LightGBM` to predict the label(such as `preds`) of test data `x_test` and return it. - Code Example: In the following example, users need to use `LightGBM` to predict the label(such as `preds`) of test data `x_test` and return it.

View File

@@ -27,7 +27,7 @@ pip install arctic # NOTE: pip may fail to resolve the right package dependency
2. Please follow following steps to download example data 2. Please follow following steps to download example data
```bash ```bash
cd examples/orderbook_data/ cd examples/orderbook_data/
gdown https://drive.google.com/uc?id=15nZF7tFT_eKVZAcMFL1qPS4jGyJflH7e # Proxies may be necessary here. gdown https://drive.google.com/uc?id=15FuUqWn2rkCi8uhJYGEQWKakcEqLJNDG # Proxies may be necessary here.
python ../../scripts/get_data.py _unzip --file_path highfreq_orderbook_example_data.zip --target_dir . python ../../scripts/get_data.py _unzip --file_path highfreq_orderbook_example_data.zip --target_dir .
``` ```

View File

@@ -1,5 +1,5 @@
[build-system] [build-system]
requires = ["setuptools", "cython", "numpy>=1.24.0"] requires = ["setuptools", "setuptools-scm", "cython", "numpy>=1.24.0"]
build-backend = "setuptools.build_meta" build-backend = "setuptools.build_meta"
[project] [project]
@@ -22,11 +22,15 @@ dynamic = ["version"]
description = "A Quantitative-research Platform" description = "A Quantitative-research Platform"
requires-python = ">=3.8.0" requires-python = ">=3.8.0"
readme = {file = "README.md", content-type = "text/markdown"} readme = {file = "README.md", content-type = "text/markdown"}
license = { text = "MIT" }
dependencies = [ dependencies = [
"pyyaml", "pyyaml",
"numpy", "numpy",
"pandas>=0.24", # Since version 1.1.0, pandas supports the ffill and bfill methods.
# Since version 2.1.0, pandas has deprecated the method parameter of the fillna method.
# qlib has updated the fillna method in PR 1987 and limited the minimum version of pandas.
"pandas>=1.1",
# I encoutered an Error that the set_uri does not work when downloading artifacts in mlflow 3.1.1; # I encoutered an Error that the set_uri does not work when downloading artifacts in mlflow 3.1.1;
# But earlier versions of mlflow does not have this problem. # But earlier versions of mlflow does not have this problem.
# But when I switch to 2.*.* version, another error occurs, which is even more strange... # But when I switch to 2.*.* version, another error occurs, which is even more strange...
@@ -49,6 +53,7 @@ dependencies = [
"nbconvert", "nbconvert",
"pyarrow", "pyarrow",
"pydantic-settings", "pydantic-settings",
"setuptools-scm",
] ]
[project.optional-dependencies] [project.optional-dependencies]
@@ -108,3 +113,8 @@ license-files = []
[project.scripts] [project.scripts]
qrun = "qlib.cli.run:run" qrun = "qlib.cli.run:run"
[tool.setuptools_scm]
local_scheme = "no-local-version"
version_scheme = "guess-next-dev"
write_to = "qlib/_version.py"

View File

@@ -2,15 +2,22 @@
# Licensed under the MIT License. # Licensed under the MIT License.
from pathlib import Path from pathlib import Path
__version__ = "0.9.7" from setuptools_scm import get_version
try:
from ._version import version as __version__
except ImportError:
__version__ = get_version(root="..", relative_to=__file__)
__version__bak = __version__ # This version is backup for QlibConfig.reset_qlib_version __version__bak = __version__ # This version is backup for QlibConfig.reset_qlib_version
import os
import re
from typing import Union
from ruamel.yaml import YAML
import logging import logging
import os
import platform import platform
import re
import subprocess import subprocess
from typing import Union
from ruamel.yaml import YAML
from .log import get_module_logger from .log import get_module_logger
@@ -136,6 +143,9 @@ def _mount_nfs_uri(provider_uri, mount_path, auto_mount: bool = False):
_command_log = [line for line in _command_log if _remote_uri in line] _command_log = [line for line in _command_log if _remote_uri in line]
if len(_command_log) > 0: if len(_command_log) > 0:
for _c in _command_log: for _c in _command_log:
if isinstance(_c, str):
_temp_mount = _c.split(" ")[2]
else:
_temp_mount = _c.decode("utf-8").split(" ")[2] _temp_mount = _c.decode("utf-8").split(" ")[2]
_temp_mount = _temp_mount[:-1] if _temp_mount.endswith("/") else _temp_mount _temp_mount = _temp_mount[:-1] if _temp_mount.endswith("/") else _temp_mount
if _temp_mount == _mount_path: if _temp_mount == _mount_path:

View File

@@ -281,13 +281,13 @@ def brinson_pa(
stock_group_field = stock_df[group_field].unstack().T stock_group_field = stock_df[group_field].unstack().T
# FIXME: some attributes of some suspend stock is NAN. # FIXME: some attributes of some suspend stock is NAN.
stock_group_field = stock_group_field.fillna(method="ffill") stock_group_field = stock_group_field.ffill()
stock_group_field = stock_group_field.loc[start_date:end_date] stock_group_field = stock_group_field.loc[start_date:end_date]
stock_group = get_stock_group(stock_group_field, bench_stock_weight, group_method, group_n) stock_group = get_stock_group(stock_group_field, bench_stock_weight, group_method, group_n)
deal_price_df = stock_df["deal_price"].unstack().T deal_price_df = stock_df["deal_price"].unstack().T
deal_price_df = deal_price_df.fillna(method="ffill") deal_price_df = deal_price_df.ffill()
# NOTE: # NOTE:
# The return will be slightly different from the of the return in the report. # The return will be slightly different from the of the return in the report.

View File

@@ -51,7 +51,7 @@ class LGBModel(ModelFT, LightGBMFInt):
w = reweighter.reweight(df) w = reweighter.reweight(df)
else: else:
raise ValueError("Unsupported reweighter type.") raise ValueError("Unsupported reweighter type.")
ds_l.append((lgb.Dataset(x.values, label=y, weight=w), key)) ds_l.append((lgb.Dataset(x.values, label=y, weight=w, free_raw_data=False), key))
return ds_l return ds_l
def fit( def fit(
@@ -109,8 +109,10 @@ class LGBModel(ModelFT, LightGBMFInt):
verbose level verbose level
""" """
# Based on existing model and finetune by train more rounds # Based on existing model and finetune by train more rounds
dtrain, _ = self._prepare_data(dataset, reweighter) # pylint: disable=W0632 ds_l = self._prepare_data(dataset, reweighter)
if dtrain.empty: dtrain, _ = ds_l[0]
if dtrain.construct().num_data() == 0:
raise ValueError("Empty data from dataset, please check your dataset config.") raise ValueError("Empty data from dataset, please check your dataset config.")
verbose_eval_callback = lgb.log_evaluation(period=verbose_eval) verbose_eval_callback = lgb.log_evaluation(period=verbose_eval)
self.model = lgb.train( self.model = lgb.train(

View File

@@ -135,7 +135,7 @@ class FFillNan(ElemOperator):
def _load_internal(self, instrument, start_index, end_index, freq): def _load_internal(self, instrument, start_index, end_index, freq):
series = self.feature.load(instrument, start_index, end_index, freq) series = self.feature.load(instrument, start_index, end_index, freq)
return series.fillna(method="ffill") return series.ffill()
class BFillNan(ElemOperator): class BFillNan(ElemOperator):
@@ -154,7 +154,7 @@ class BFillNan(ElemOperator):
def _load_internal(self, instrument, start_index, end_index, freq): def _load_internal(self, instrument, start_index, end_index, freq):
series = self.feature.load(instrument, start_index, end_index, freq) series = self.feature.load(instrument, start_index, end_index, freq)
return series.fillna(method="bfill") return series.bfill()
class Date(ElemOperator): class Date(ElemOperator):

View File

@@ -33,7 +33,7 @@ def parse_position(position: dict = None) -> pd.DataFrame:
position_weight_df = get_stock_weight_df(position) position_weight_df = get_stock_weight_df(position)
# If the day does not exist, use the last weight # If the day does not exist, use the last weight
position_weight_df.fillna(method="ffill", inplace=True) position_weight_df.ffill(inplace=True)
previous_data = {"date": None, "code_list": []} previous_data = {"date": None, "code_list": []}

View File

@@ -67,7 +67,6 @@ class NaiveDFStorage(BaseHandlerStorage):
col_set: Union[str, List[str]] = DataHandler.CS_ALL, col_set: Union[str, List[str]] = DataHandler.CS_ALL,
fetch_orig: bool = True, fetch_orig: bool = True,
) -> pd.DataFrame: ) -> pd.DataFrame:
# Following conflicts may occur # Following conflicts may occur
# - Does [20200101", "20210101"] mean selecting this slice or these two days? # - Does [20200101", "20210101"] mean selecting this slice or these two days?
# To solve this issue # To solve this issue

View File

@@ -161,7 +161,6 @@ def init_instance_by_config(
# path like 'file:///<path to pickle file>/obj.pkl' # path like 'file:///<path to pickle file>/obj.pkl'
pr = urlparse(config) pr = urlparse(config)
if pr.scheme == "file": if pr.scheme == "file":
# To enable relative path like file://data/a/b/c.pkl. pr.netloc will be data # To enable relative path like file://data/a/b/c.pkl. pr.netloc will be data
path = pr.path path = pr.path
if pr.netloc != "": if pr.netloc != "":

View File

@@ -109,7 +109,7 @@ def resam_ts_data(
""" """
Resample value from time-series data Resample value from time-series data
- If `feature` has MultiIndex[instrument, datetime], apply the `method` to each instruemnt data with datetime in [start_time, end_time] - If `feature` has MultiIndex[instrument, datetime], apply the `method` to each instrument data with datetime in [start_time, end_time]
Example: Example:
.. code-block:: .. code-block::
@@ -222,7 +222,7 @@ def get_valid_value(series, last=True):
Nan | float Nan | float
the first/last valid value the first/last valid value
""" """
return series.fillna(method="ffill").iloc[-1] if last else series.fillna(method="bfill").iloc[0] return series.ffill().iloc[-1] if last else series.bfill().iloc[0]
def _ts_data_valid(ts_feature, last=False): def _ts_data_valid(ts_feature, last=False):

View File

@@ -28,32 +28,32 @@ class InfoCollector:
"""collect qlib related info""" """collect qlib related info"""
print("Qlib version: {}".format(qlib.__version__)) print("Qlib version: {}".format(qlib.__version__))
REQUIRED = [ REQUIRED = [
"setuptools",
"wheel",
"cython",
"pyyaml",
"numpy", "numpy",
"pandas", "pandas",
"scipy",
"requests",
"sacred",
"python-socketio",
"redis",
"python-redis-lock",
"schedule",
"cvxpy",
"hyperopt",
"fire",
"statsmodels",
"xlrd",
"plotly",
"matplotlib",
"tables",
"pyyaml",
"mlflow", "mlflow",
"tqdm", "filelock",
"loguru", "redis",
"lightgbm", "dill",
"tornado",
"joblib",
"fire", "fire",
"ruamel.yaml", "ruamel.yaml",
"python-redis-lock",
"tqdm",
"pymongo",
"loguru",
"lightgbm",
"gym",
"cvxpy",
"joblib",
"matplotlib",
"jupyter",
"nbconvert",
"pyarrow",
"pydantic-settings",
"setuptools-scm",
] ]
for package in REQUIRED: for package in REQUIRED:

View File

@@ -172,7 +172,7 @@ class BaostockNormalizeHS3005min(BaseNormalize):
@staticmethod @staticmethod
def calc_change(df: pd.DataFrame, last_close: float) -> pd.Series: def calc_change(df: pd.DataFrame, last_close: float) -> pd.Series:
df = df.copy() df = df.copy()
_tmp_series = df["close"].fillna(method="ffill") _tmp_series = df["close"].ffill()
_tmp_shift_series = _tmp_series.shift(1) _tmp_shift_series = _tmp_series.shift(1)
if last_close is not None: if last_close is not None:
_tmp_shift_series.iloc[0] = float(last_close) _tmp_shift_series.iloc[0] = float(last_close)

View File

@@ -82,7 +82,7 @@ def get_calendar_list(bench_code="CSI300") -> List[pd.Timestamp]:
if bench_code.upper() == "ALL": if bench_code.upper() == "ALL":
@deco_retry @deco_retry
def _get_calendar(month): def _get_calendar_from_month(month):
_cal = [] _cal = []
try: try:
resp = requests.get( resp = requests.get(
@@ -98,7 +98,7 @@ def get_calendar_list(bench_code="CSI300") -> List[pd.Timestamp]:
month_range = pd.date_range(start="2000-01", end=pd.Timestamp.now() + pd.Timedelta(days=31), freq="M") month_range = pd.date_range(start="2000-01", end=pd.Timestamp.now() + pd.Timedelta(days=31), freq="M")
calendar = [] calendar = []
for _m in month_range: for _m in month_range:
cal = _get_calendar(_m.strftime("%Y-%m")) cal = _get_calendar_from_month(_m.strftime("%Y-%m"))
if cal: if cal:
calendar += cal calendar += cal
calendar = list(filter(lambda x: x <= pd.Timestamp.now(), calendar)) calendar = list(filter(lambda x: x <= pd.Timestamp.now(), calendar))

View File

@@ -371,7 +371,7 @@ class YahooNormalize(BaseNormalize):
@staticmethod @staticmethod
def calc_change(df: pd.DataFrame, last_close: float) -> pd.Series: def calc_change(df: pd.DataFrame, last_close: float) -> pd.Series:
df = df.copy() df = df.copy()
_tmp_series = df["close"].fillna(method="ffill") _tmp_series = df["close"].ffill()
_tmp_shift_series = _tmp_series.shift(1) _tmp_shift_series = _tmp_series.shift(1)
if last_close is not None: if last_close is not None:
_tmp_shift_series.iloc[0] = float(last_close) _tmp_shift_series.iloc[0] = float(last_close)
@@ -459,7 +459,7 @@ class YahooNormalize1d(YahooNormalize, ABC):
df.set_index(self._date_field_name, inplace=True) df.set_index(self._date_field_name, inplace=True)
if "adjclose" in df: if "adjclose" in df:
df["factor"] = df["adjclose"] / df["close"] df["factor"] = df["adjclose"] / df["close"]
df["factor"] = df["factor"].fillna(method="ffill") df["factor"] = df["factor"].ffill()
else: else:
df["factor"] = 1 df["factor"] = 1
for _col in self.COLUMNS: for _col in self.COLUMNS:
@@ -613,10 +613,6 @@ class YahooNormalize1min(YahooNormalize, ABC):
def symbol_to_yahoo(self, symbol): def symbol_to_yahoo(self, symbol):
raise NotImplementedError("rewrite symbol_to_yahoo") raise NotImplementedError("rewrite symbol_to_yahoo")
@abc.abstractmethod
def _get_1d_calendar_list(self) -> Iterable[pd.Timestamp]:
raise NotImplementedError("rewrite _get_1d_calendar_list")
class YahooNormalizeUS: class YahooNormalizeUS:
def _get_calendar_list(self) -> Iterable[pd.Timestamp]: def _get_calendar_list(self) -> Iterable[pd.Timestamp]:

View File

@@ -1,29 +1,13 @@
from setuptools import setup, Extension
import numpy
import os import os
import numpy
def read(rel_path: str) -> str: from setuptools import Extension, setup
here = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(here, rel_path), encoding="utf-8") as fp:
return fp.read()
def get_version(rel_path: str) -> str:
for line in read(rel_path).splitlines():
if line.startswith("__version__"):
delim = '"' if '"' in line else "'"
return line.split(delim)[1]
raise RuntimeError("Unable to find version string.")
NUMPY_INCLUDE = numpy.get_include() NUMPY_INCLUDE = numpy.get_include()
VERSION = get_version("qlib/__init__.py")
setup( setup(
version=VERSION,
ext_modules=[ ext_modules=[
Extension( Extension(
"qlib.data._libs.rolling", "qlib.data._libs.rolling",