From 1b138c559e66e4edf8f23d03e4703a163cd00e46 Mon Sep 17 00:00:00 2001 From: Tim Paine <3105306+timkpaine@users.noreply.github.com> Date: Sun, 23 Jun 2024 22:39:40 -0400 Subject: [PATCH 1/2] Update ruff usage, enforce format, update workflows --- .github/dependabot.yml | 6 ++++++ .github/workflows/build.yml | 8 ++++---- .github/workflows/deploy.yml | 4 +--- .github/workflows/regression.yml | 8 ++++---- Makefile | 3 ++- pyproject.toml | 2 +- setup.py | 5 ++++- 7 files changed, 22 insertions(+), 14 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5ace4600..9d2674e5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,9 @@ updates: directory: "/" schedule: interval: "weekly" + + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "monthly" + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ce1b10c6..576ce97f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,9 @@ jobs: python-version: [3.11] steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: @@ -31,9 +33,7 @@ jobs: cache-dependency-path: 'setup.py' - name: Install dependencies - run: | - make develop - python -m pip install -U wheel twine setuptools + run: make develop - name: Lint run: make lint diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 941d7989..c93f1861 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -146,9 +146,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies - run: | - make develop - python -m pip install -U wheel twine setuptools + run: make develop - name: Python SDist Steps run: python setup.py sdist diff --git a/.github/workflows/regression.yml b/.github/workflows/regression.yml index 3da47f8d..1c4303ab 100644 --- a/.github/workflows/regression.yml +++ b/.github/workflows/regression.yml @@ -31,7 +31,9 @@ jobs: pandas_version: '<2' steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: @@ -40,9 +42,7 @@ jobs: cache-dependency-path: 'setup.py' - name: Install dependencies - run: | - make develop - python -m pip install -U wheel twine setuptools "numpy${{ matrix.numpy_version }}" "pandas${{ matrix.pandas_version}}" + run: make develop - name: Test run: make test diff --git a/Makefile b/Makefile index 25f507c8..9cd9a738 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,8 @@ test: python -m pytest -vvv tests --cov=bt --junitxml=python_junit.xml --cov-report=xml --cov-branch --cov-report term lint: - python -m ruff bt setup.py docs/source/conf.py + python -m ruff check bt setup.py docs/source/conf.py + python -m ruff format --check bt setup.py docs/source/conf.py fix: python -m ruff format bt setup.py docs/source/conf.py diff --git a/pyproject.toml b/pyproject.toml index fa5ab7b6..df906df7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,5 +4,5 @@ requires = ["setuptools", "wheel", "cython>=0.29.25"] [tool.ruff] line-length = 180 -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "__init__.py" = ["F401", "F403"] diff --git a/setup.py b/setup.py index acb8813c..e7b48d6f 100644 --- a/setup.py +++ b/setup.py @@ -47,7 +47,10 @@ def local_file(filename): "pyprind>=2.11", "pytest", "pytest-cov", - "ruff", + "ruff>=0.3,<0.5", + "setuptools", + "twine", + "wheel", ], }, packages=["bt"], From 8d57f199df688795b9ae7bc17653827266942470 Mon Sep 17 00:00:00 2001 From: Tim Paine <3105306+timkpaine@users.noreply.github.com> Date: Sun, 23 Jun 2024 22:39:46 -0400 Subject: [PATCH 2/2] Reformat files --- bt/algos.py | 49 +------------------------------------------------ bt/backtest.py | 4 +--- bt/core.py | 7 +------ setup.py | 6 +----- 4 files changed, 4 insertions(+), 62 deletions(-) diff --git a/bt/algos.py b/bt/algos.py index 8b6e7875..8daa414c 100644 --- a/bt/algos.py +++ b/bt/algos.py @@ -1,6 +1,7 @@ """ A collection of Algos used to create Strategy logic. """ + from __future__ import division import abc @@ -26,7 +27,6 @@ def run_always(f): class PrintDate(Algo): - """ This Algo simply print's the current date. @@ -39,7 +39,6 @@ def __call__(self, target): class PrintTempData(Algo): - """ This Algo prints the temp data. @@ -64,7 +63,6 @@ def __call__(self, target): class PrintInfo(Algo): - """ Prints out info associated with the target strategy. Useful for debugging purposes. @@ -93,7 +91,6 @@ def __call__(self, target): class Debug(Algo): - """ Utility Algo that calls pdb.set_trace when triggered. @@ -109,7 +106,6 @@ def __call__(self, target): class RunOnce(Algo): - """ Returns True on first run then returns False. @@ -192,7 +188,6 @@ def compare_dates(self, now, date_to_compare): class RunDaily(RunPeriod): - """ Returns True on day change. @@ -215,7 +210,6 @@ def compare_dates(self, now, date_to_compare): class RunWeekly(RunPeriod): - """ Returns True on week change. @@ -238,7 +232,6 @@ def compare_dates(self, now, date_to_compare): class RunMonthly(RunPeriod): - """ Returns True on month change. @@ -261,7 +254,6 @@ def compare_dates(self, now, date_to_compare): class RunQuarterly(RunPeriod): - """ Returns True on quarter change. @@ -284,7 +276,6 @@ def compare_dates(self, now, date_to_compare): class RunYearly(RunPeriod): - """ Returns True on year change. @@ -307,7 +298,6 @@ def compare_dates(self, now, date_to_compare): class RunOnDate(Algo): - """ Returns True on a specific set of dates. @@ -332,7 +322,6 @@ def __call__(self, target): class RunAfterDate(Algo): - """ Returns True after a date has passed @@ -359,7 +348,6 @@ def __call__(self, target): class RunAfterDays(Algo): - """ Returns True after a specific number of 'warmup' trading days have passed @@ -388,7 +376,6 @@ def __call__(self, target): class RunIfOutOfBounds(Algo): - """ This algo returns true if any of the target weights deviate by an amount greater than tolerance. For example, it will be run if the tolerance is set to 0.5 and @@ -433,7 +420,6 @@ def __call__(self, target): class RunEveryNPeriods(Algo): - """ This algo runs every n periods. @@ -473,7 +459,6 @@ def __call__(self, target): class SelectAll(Algo): - """ Sets temp['selected'] with all securities (based on universe). @@ -508,7 +493,6 @@ def __call__(self, target): class SelectThese(Algo): - """ Sets temp['selected'] with a set list of tickers. @@ -542,7 +526,6 @@ def __call__(self, target): class SelectHasData(Algo): - """ Sets temp['selected'] based on all items in universe that meet data requirements. @@ -611,7 +594,6 @@ def __call__(self, target): class SelectN(Algo): - """ Sets temp['selected'] based on ranking temp['stat']. @@ -668,7 +650,6 @@ def __call__(self, target): class SelectMomentum(AlgoStack): - """ Sets temp['selected'] based on a simple momentum filter. @@ -711,7 +692,6 @@ def __init__( class SelectWhere(Algo): - """ Selects securities based on an indicator DataFrame. @@ -771,7 +751,6 @@ def __call__(self, target): class SelectRandomly(AlgoStack): - """ Sets temp['selected'] based on a random subset of the items currently in temp['selected']. @@ -831,7 +810,6 @@ def __call__(self, target): class SelectRegex(Algo): - """ Sets temp['selected'] based on a regex on their names. Useful when working with a large universe of different kinds of securities @@ -858,7 +836,6 @@ def __call__(self, target): class ResolveOnTheRun(Algo): - """ Looks at securities set in temp['selected'] and searches for names that match the names of "aliases" for on-the-run securities in the provided @@ -905,7 +882,6 @@ def __call__(self, target): class SetStat(Algo): - """ Sets temp['stat'] for use by downstream algos (such as SelectN). @@ -935,7 +911,6 @@ def __call__(self, target): class StatTotalReturn(Algo): - """ Sets temp['stat'] with total returns over a given period. @@ -972,7 +947,6 @@ def __call__(self, target): class WeighEqually(Algo): - """ Sets temp['weights'] by calculating equal weights for all items in selected. @@ -1004,7 +978,6 @@ def __call__(self, target): class WeighSpecified(Algo): - """ Sets temp['weights'] based on a provided dict of ticker:weights. @@ -1029,7 +1002,6 @@ def __call__(self, target): class ScaleWeights(Algo): - """ Sets temp['weights'] based on a scaled version of itself. Useful for going short, or scaling up/down when using @@ -1056,7 +1028,6 @@ def __call__(self, target): class WeighTarget(Algo): - """ Sets target weights based on a target weight DataFrame. @@ -1110,7 +1081,6 @@ def __call__(self, target): class WeighInvVol(Algo): - """ Sets temp['weights'] based on the inverse volatility Algo. @@ -1154,7 +1124,6 @@ def __call__(self, target): class WeighERC(Algo): - """ Sets temp['weights'] based on equal risk contribution algorithm. @@ -1241,7 +1210,6 @@ def __call__(self, target): class WeighMeanVar(Algo): - """ Sets temp['weights'] based on mean-variance optimization. @@ -1307,7 +1275,6 @@ def __call__(self, target): class WeighRandomly(Algo): - """ Sets temp['weights'] based on a random weight vector. @@ -1356,7 +1323,6 @@ def __call__(self, target): class LimitDeltas(Algo): - """ Modifies temp['weights'] based on weight delta limits. @@ -1415,7 +1381,6 @@ def __call__(self, target): class LimitWeights(Algo): - """ Modifies temp['weights'] based on weight limits. @@ -1619,7 +1584,6 @@ def __call__(self, target): class CapitalFlow(Algo): - """ Used to model capital flows. Flows can either be inflows or outflows. @@ -1652,7 +1616,6 @@ def __call__(self, target): class CloseDead(Algo): - """ Closes all positions for which prices are equal to zero (we assume that these stocks are dead) and removes them from temp['weights'] if @@ -1689,7 +1652,6 @@ def __call__(self, target): class SetNotional(Algo): - """ Sets the notional_value to use as the base for rebalancing for :class:`FixedIncomeStrategy ` targets @@ -1718,7 +1680,6 @@ def __call__(self, target): class Rebalance(Algo): - """ Rebalances capital based on temp['weights'] @@ -1792,7 +1753,6 @@ def __call__(self, target): class RebalanceOverTime(Algo): - """ Similar to Rebalance but rebalances to target weight over n periods. @@ -1862,7 +1822,6 @@ def __call__(self, target): class Require(Algo): - """ Flow control Algo. @@ -1984,7 +1943,6 @@ def __call__(self, target): class ClosePositionsAfterDates(Algo): - """ Close positions on securities after a given date. This can be used to make sure positions on matured/redeemed securities are @@ -2037,7 +1995,6 @@ def __call__(self, target): class RollPositionsAfterDates(Algo): - """ Roll securities based on the provided map. This can be used for any securities which have "On-The-Run" and "Off-The-Run" @@ -2095,7 +2052,6 @@ def __call__(self, target): class SelectActive(Algo): - """ Sets temp['selected'] based on filtering temp['selected'] to exclude those securities that have been closed or rolled after a certain date @@ -2121,7 +2077,6 @@ def __call__(self, target): class ReplayTransactions(Algo): - """ Replay a list of transactions that were executed. This is useful for taking a blotter of actual trades that occurred, @@ -2227,7 +2182,6 @@ def _get_unit_risk(security, data, index=None): class UpdateRisk(Algo): - """ Tracks a risk measure on all nodes of the strategy. To use this node, the ``additional_data`` argument on :class:`Backtest ` must @@ -2298,7 +2252,6 @@ def __call__(self, target): class PrintRisk(Algo): - """ This Algo prints the risk data. diff --git a/bt/backtest.py b/bt/backtest.py index 68481031..e531a53e 100644 --- a/bt/backtest.py +++ b/bt/backtest.py @@ -1,6 +1,7 @@ """ Contains backtesting logic and objects. """ + from __future__ import division from copy import deepcopy import bt @@ -81,7 +82,6 @@ def benchmark_random(backtest, random_strategy, nsim=100): class Backtest(object): - """ A Backtest combines a Strategy with data to produce a Result. @@ -359,7 +359,6 @@ def turnover(self): class Result(ffn.GroupStats): - """ Based on ffn's GroupStats with a few extra helper methods. @@ -508,7 +507,6 @@ def get_transactions(self, strategy_name=None): class RandomBenchmarkResult(Result): - """ RandomBenchmarkResult expands on Result to add methods specific to random strategy benchmarking. diff --git a/bt/core.py b/bt/core.py index 901d54c9..a00676cc 100644 --- a/bt/core.py +++ b/bt/core.py @@ -1,6 +1,7 @@ """ Contains the core building blocks of the framework. """ + from __future__ import division import math @@ -24,7 +25,6 @@ def is_zero(x): class Node(object): - """ The Node is the main building block in bt's tree structure design. Both StrategyBase and SecurityBase inherit Node. It contains the @@ -321,7 +321,6 @@ def to_dot(self, root=True): class StrategyBase(Node): - """ Strategy Node. Used to define strategy logic within a tree. A Strategy's role is to allocate capital to it's children @@ -1127,7 +1126,6 @@ def _create_child_if_needed(self, child): class SecurityBase(Node): - """ Security Node. Used to define a security within a tree. A Security's has no children. It simply models an asset that can be bought @@ -1945,7 +1943,6 @@ def update(self, date, data=None, inow=None): class Algo(object): - """ Algos are used to modularize strategy logic so that strategy logic becomes modular, composable, more testable and less error prone. Basically, the @@ -1981,7 +1978,6 @@ def __call__(self, target): class AlgoStack(Algo): - """ An AlgoStack derives from Algo runs multiple Algos until a failure is encountered. @@ -2022,7 +2018,6 @@ def __call__(self, target): class Strategy(StrategyBase): - """ Strategy expands on the StrategyBase and incorporates Algos. diff --git a/setup.py b/setup.py index e7b48d6f..f3f2111f 100644 --- a/setup.py +++ b/setup.py @@ -32,11 +32,7 @@ def local_file(filename): keywords="python finance quant backtesting strategies algotrading algorithmic trading", url="https://github.com/pmorissette/bt", license="MIT", - install_requires=[ - "ffn>=1.0.0", - "pyprind>=2.11", - "tqdm>=4" - ], + install_requires=["ffn>=1.0.0", "pyprind>=2.11", "tqdm>=4"], extras_require={ "dev": [ "cython>=0.29.25",