quantflow 0.2.5__tar.gz → 0.2.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. {quantflow-0.2.5 → quantflow-0.2.7}/PKG-INFO +16 -7
  2. {quantflow-0.2.5 → quantflow-0.2.7}/pyproject.toml +29 -34
  3. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/__init__.py +1 -1
  4. quantflow-0.2.7/quantflow/cli/__init__.py +131 -0
  5. quantflow-0.2.7/quantflow/cli/settings.py +11 -0
  6. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/data/client.py +2 -2
  7. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/data/fmp.py +11 -5
  8. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/sp/poisson.py +1 -1
  9. quantflow-0.2.7/quantflow/utils/df.py +72 -0
  10. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/utils/plot.py +15 -0
  11. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/utils/types.py +3 -2
  12. {quantflow-0.2.5 → quantflow-0.2.7}/readme.md +6 -0
  13. {quantflow-0.2.5 → quantflow-0.2.7}/LICENSE +0 -0
  14. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/data/__init__.py +0 -0
  15. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/options/__init__.py +0 -0
  16. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/options/bs.py +0 -0
  17. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/options/calibration.py +0 -0
  18. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/options/inputs.py +0 -0
  19. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/options/pricer.py +0 -0
  20. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/options/surface.py +0 -0
  21. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/py.typed +0 -0
  22. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/sp/__init__.py +0 -0
  23. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/sp/base.py +0 -0
  24. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/sp/bns.py +0 -0
  25. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/sp/cir.py +0 -0
  26. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/sp/copula.py +0 -0
  27. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/sp/dsp.py +0 -0
  28. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/sp/heston.py +0 -0
  29. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/sp/jump_diffusion.py +0 -0
  30. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/sp/ou.py +0 -0
  31. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/sp/weiner.py +0 -0
  32. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/utils/__init__.py +0 -0
  33. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/utils/bins.py +0 -0
  34. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/utils/dates.py +0 -0
  35. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/utils/distributions.py +0 -0
  36. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/utils/functions.py +0 -0
  37. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/utils/interest_rates.py +0 -0
  38. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/utils/marginal.py +0 -0
  39. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/utils/numbers.py +0 -0
  40. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/utils/paths.py +0 -0
  41. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/utils/transforms.py +0 -0
  42. {quantflow-0.2.5 → quantflow-0.2.7}/quantflow/utils/volatility.py +0 -0
@@ -1,23 +1,26 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: quantflow
3
- Version: 0.2.5
3
+ Version: 0.2.7
4
4
  Summary: quantitative analysis
5
5
  License: BSD-3-Clause
6
6
  Author: Luca
7
7
  Author-email: luca@quantmind.com
8
- Requires-Python: >=3.10,<3.13
8
+ Requires-Python: >=3.11
9
9
  Classifier: License :: OSI Approved :: BSD License
10
10
  Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.10
12
11
  Classifier: Programming Language :: Python :: 3.11
13
12
  Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
14
  Provides-Extra: data
15
15
  Requires-Dist: aiohttp (>=3.8.1,<4.0.0) ; extra == "data"
16
- Requires-Dist: numpy (>=1.22.3,<2.0.0)
17
- Requires-Dist: pandas (>=2.0.1,<3.0.0)
18
- Requires-Dist: pyarrow (>=15.0.0,<16.0.0)
16
+ Requires-Dist: asciichart (>=0.1,<0.2)
17
+ Requires-Dist: asciichartpy (>=1.5.25,<2.0.0)
18
+ Requires-Dist: ccy[cli] (==1.6.0)
19
+ Requires-Dist: polars[pandas,pyarrow] (==1.11.0)
20
+ Requires-Dist: prompt-toolkit (>=3.0.43,<4.0.0)
19
21
  Requires-Dist: pydantic (>=2.0.2,<3.0.0)
20
- Requires-Dist: scipy (>=1.10.1,<2.0.0)
22
+ Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
23
+ Requires-Dist: scipy (>=1.14.1,<2.0.0)
21
24
  Project-URL: Documentation, https://quantmind.github.io/quantflow/
22
25
  Project-URL: Homepage, https://github.com/quantmind/quantflow
23
26
  Project-URL: Repository, https://github.com/quantmind/quantflow
@@ -50,3 +53,9 @@ pip install quantflow
50
53
  * [quantflow.options](https://github.com/quantmind/quantflow/tree/main/quantflow/options) option pricing and calibration
51
54
  * [quantflow.sp](https://github.com/quantmind/quantflow/tree/main/quantflow/sp) stochastic process primitives
52
55
 
56
+
57
+ ## Command line tools
58
+
59
+ When installing with the extra `data` dependencies, it is possible to use the command line tool `qf`
60
+
61
+
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "quantflow"
3
- version = "0.2.5"
3
+ version = "0.2.7"
4
4
  description = "quantitative analysis"
5
5
  authors = ["Luca <luca@quantmind.com>"]
6
6
  license = "BSD-3-Clause"
@@ -12,21 +12,24 @@ Repository = "https://github.com/quantmind/quantflow"
12
12
  Documentation = "https://quantmind.github.io/quantflow/"
13
13
 
14
14
  [tool.poetry.dependencies]
15
- python = ">=3.10,<3.13"
16
- numpy = "^1.22.3"
17
- scipy = "^1.10.1"
18
- pandas = "^2.0.1"
15
+ python = ">=3.11"
16
+ scipy = "^1.14.1"
19
17
  aiohttp = {version = "^3.8.1", optional = true}
20
18
  pydantic = "^2.0.2"
21
- pyarrow = "^15.0.0"
19
+ ccy = {version="1.6.0", extras=["cli"]}
20
+ asciichart = "^0.1"
21
+ python-dotenv = "^1.0.1"
22
+ asciichartpy = "^1.5.25"
23
+ prompt-toolkit = "^3.0.43"
24
+ polars = {version = "1.11.0", extras=["pandas", "pyarrow"]}
22
25
 
23
26
  [tool.poetry.group.dev.dependencies]
24
27
  black = "^24.1.1"
25
- pytest-cov = "^4.0.0"
26
- mypy = "^1.4.0"
28
+ pytest-cov = "^5.0.0"
29
+ mypy = "^1.13.0"
27
30
  ghp-import = "^2.0.2"
28
- ruff = "^0.1.14"
29
- pytest-asyncio = "^0.23.3"
31
+ ruff = "^0.7.1"
32
+ pytest-asyncio = "^0.24.0"
30
33
 
31
34
 
32
35
  [tool.poetry.extras]
@@ -36,14 +39,17 @@ data = ["aiohttp"]
36
39
  optional = true
37
40
 
38
41
  [tool.poetry.group.book.dependencies]
39
- jupyter-book = "^0.15.1"
40
- nbconvert = "^6.4.5"
42
+ jupyter-book = "^1.0.0"
43
+ nbconvert = "^7.16.3"
41
44
  jupytext = "^1.13.8"
42
- plotly = "^5.7.0"
45
+ plotly = "^5.20.0"
43
46
  jupyterlab = "^4.0.2"
44
47
  sympy = "^1.12"
45
48
  ipywidgets = "^8.0.7"
46
49
 
50
+ [tool.poetry.scripts]
51
+ qf = "quantflow.cli:main"
52
+
47
53
  [build-system]
48
54
  requires = ["poetry-core>=1.0.0"]
49
55
  build-backend = "poetry.core.masonry.api"
@@ -56,15 +62,12 @@ asyncio_mode = "auto"
56
62
  testpaths = [
57
63
  "quantflow_tests"
58
64
  ]
59
- filterwarnings = [
60
- "ignore::DeprecationWarning:dateutil.*:"
61
- ]
62
65
 
63
66
  [tool.isort]
64
67
  profile = "black"
65
68
 
66
69
  [tool.ruff]
67
- select = ["E", "F"]
70
+ lint.select = ["E", "F"]
68
71
  extend-exclude = ["fluid_apps/db/migrations"]
69
72
  line-length = 88
70
73
 
@@ -78,21 +81,13 @@ disallow_untyped_defs = true
78
81
  warn_no_return = true
79
82
 
80
83
  [[tool.mypy.overrides]]
81
- module = "quantflow_tests.*"
82
- disallow_untyped_defs = false
83
-
84
- [[tool.mypy.overrides]]
85
- module = "IPython.*"
86
- ignore_missing_imports = true
87
-
88
- [[tool.mypy.overrides]]
89
- module = "pandas.*"
90
- ignore_missing_imports = true
91
-
92
- [[tool.mypy.overrides]]
93
- module = "plotly.*"
94
- ignore_missing_imports = true
95
-
96
- [[tool.mypy.overrides]]
97
- module = "scipy.*"
84
+ module = [
85
+ "asciichartpy.*",
86
+ "quantflow_tests.*",
87
+ "IPython.*",
88
+ "pandas.*",
89
+ "plotly.*",
90
+ "scipy.*"
91
+ ]
98
92
  ignore_missing_imports = true
93
+ disallow_untyped_defs = false
@@ -1,3 +1,3 @@
1
1
  """Quantitative analysis and pricing"""
2
2
 
3
- __version__ = "0.2.5"
3
+ __version__ = "0.2.7"
@@ -0,0 +1,131 @@
1
+ import asyncio
2
+ import os
3
+ from dataclasses import dataclass, field
4
+ from typing import Any
5
+
6
+ import click
7
+ import dotenv
8
+ import pandas as pd
9
+ from asciichartpy import plot
10
+ from ccy.cli.console import df_to_rich
11
+ from prompt_toolkit import PromptSession
12
+ from prompt_toolkit.history import FileHistory
13
+ from rich.console import Console
14
+ from rich.text import Text
15
+
16
+ from quantflow.data.fmp import FMP
17
+
18
+ from . import settings
19
+
20
+ dotenv.load_dotenv()
21
+
22
+ FREQUENCIES = tuple(FMP().historical_frequencies())
23
+
24
+
25
+ @click.group()
26
+ def qf() -> None:
27
+ pass
28
+
29
+
30
+ @qf.command()
31
+ @click.argument("symbol")
32
+ def profile(symbol: str) -> None:
33
+ """Company profile"""
34
+ data = asyncio.run(get_profile(symbol))[0]
35
+ main.print(data.pop("description"))
36
+ df = pd.DataFrame(data.items(), columns=["Key", "Value"])
37
+ main.print(df_to_rich(df))
38
+
39
+
40
+ @qf.command()
41
+ @click.argument("symbol")
42
+ @click.option(
43
+ "-h",
44
+ "--height",
45
+ type=int,
46
+ default=20,
47
+ show_default=True,
48
+ help="Chart height",
49
+ )
50
+ @click.option(
51
+ "-l",
52
+ "--length",
53
+ type=int,
54
+ default=100,
55
+ show_default=True,
56
+ help="Number of data points",
57
+ )
58
+ @click.option(
59
+ "-f",
60
+ "--frequency",
61
+ type=click.Choice(FREQUENCIES),
62
+ default="",
63
+ help="Number of data points",
64
+ )
65
+ def chart(symbol: str, height: int, length: int, frequency: str) -> None:
66
+ """Symbol chart"""
67
+ df = asyncio.run(get_prices(symbol, frequency))
68
+ data = list(reversed(df["close"].tolist()[:length]))
69
+ print(plot(data, {"height": height}))
70
+
71
+
72
+ async def get_prices(symbol: str, frequency: str) -> pd.DataFrame:
73
+ async with FMP() as cli:
74
+ return await cli.prices(symbol, frequency)
75
+
76
+
77
+ async def get_profile(symbol: str) -> list[dict]:
78
+ async with FMP() as cli:
79
+ return await cli.profile(symbol)
80
+
81
+
82
+ @dataclass
83
+ class App:
84
+ console: Console = field(default_factory=Console)
85
+
86
+ def __call__(self) -> None:
87
+ os.makedirs(settings.SETTINGS_DIRECTORY, exist_ok=True)
88
+ history = FileHistory(str(settings.HIST_FILE_PATH))
89
+ session: PromptSession = PromptSession(history=history)
90
+
91
+ self.print("Welcome to QuantFlow!", style="bold green")
92
+ self.handle_command("help")
93
+
94
+ try:
95
+ while True:
96
+ try:
97
+ text = session.prompt("quantflow> ")
98
+ except KeyboardInterrupt:
99
+ break
100
+ else:
101
+ self.handle_command(text)
102
+ except click.Abort:
103
+ self.console.print(Text("Bye!", style="bold magenta"))
104
+
105
+ def print(self, text_alike: Any, style: str = "") -> None:
106
+ if isinstance(text_alike, str):
107
+ style = style or "cyan"
108
+ text_alike = Text(f"\n{text_alike}\n", style="cyan")
109
+ self.console.print(text_alike)
110
+
111
+ def error(self, err: str | Exception) -> None:
112
+ self.console.print(Text(f"\n{err}\n", style="bold red"))
113
+
114
+ def handle_command(self, text: str) -> None:
115
+ self.current_command = text.split(" ")[0].strip()
116
+ if not text:
117
+ return
118
+ elif text == "help":
119
+ return qf.main(["--help"], standalone_mode=False)
120
+ elif text == "exit":
121
+ raise click.Abort()
122
+
123
+ try:
124
+ qf.main(text.split(), standalone_mode=False)
125
+ except click.exceptions.MissingParameter as e:
126
+ self.error(e)
127
+ except click.exceptions.NoSuchOption as e:
128
+ self.error(e)
129
+
130
+
131
+ main = App()
@@ -0,0 +1,11 @@
1
+ # IMPORTATION STANDARD
2
+ from pathlib import Path
3
+
4
+ # Installation related paths
5
+ HOME_DIRECTORY = Path.home()
6
+ PACKAGE_DIRECTORY = Path(__file__).parent.parent.parent
7
+ REPOSITORY_DIRECTORY = PACKAGE_DIRECTORY.parent
8
+
9
+ SETTINGS_DIRECTORY = HOME_DIRECTORY / ".quantflow"
10
+ SETTINGS_ENV_FILE = SETTINGS_DIRECTORY / ".env"
11
+ HIST_FILE_PATH = SETTINGS_DIRECTORY / ".quantflow.his"
@@ -1,7 +1,7 @@
1
1
  import json
2
2
  import os
3
3
  from dataclasses import dataclass
4
- from typing import Any
4
+ from typing import Any, Self
5
5
 
6
6
  from aiohttp import ClientResponse, ClientSession
7
7
  from aiohttp.client_exceptions import ContentTypeError
@@ -52,7 +52,7 @@ class HttpClient:
52
52
  await self.session.close()
53
53
  self.session = None
54
54
 
55
- async def __aenter__(self) -> "HttpClient":
55
+ async def __aenter__(self) -> Self:
56
56
  return self
57
57
 
58
58
  async def __aexit__(self, *args: Any) -> None:
@@ -1,5 +1,5 @@
1
1
  import os
2
- from dataclasses import dataclass
2
+ from dataclasses import dataclass, field
3
3
  from datetime import date, timedelta
4
4
  from typing import Any, cast
5
5
 
@@ -12,7 +12,7 @@ from .client import HttpClient, compact
12
12
  @dataclass
13
13
  class FMP(HttpClient):
14
14
  url: str = "https://financialmodelingprep.com/api"
15
- key: str = os.environ.get("FMP_API_KEY", "")
15
+ key: str = field(default_factory=lambda: os.environ.get("FMP_API_KEY", ""))
16
16
 
17
17
  async def stocks(self, **kw: Any) -> list[dict]:
18
18
  return await self.get_path("v3/stock/list", **kw)
@@ -62,7 +62,7 @@ class FMP(HttpClient):
62
62
  # Rating
63
63
 
64
64
  async def rating(self, ticker: str, **kw: Any) -> list[dict]:
65
- """Company quote - real time"""
65
+ """Company rating - real time"""
66
66
  return await self.get_path(f"v3/rating/{ticker}", **kw)
67
67
 
68
68
  async def etf_holders(self, ticker: str, **kw: Any) -> list[dict]:
@@ -111,7 +111,9 @@ class FMP(HttpClient):
111
111
  **self.params(compact(query=query, exchange=exchange, limit=limit), **kw),
112
112
  )
113
113
 
114
- async def prices(self, ticker: str, frequency: str = "", **kw: Any) -> pd.DataFrame:
114
+ async def prices(
115
+ self, ticker: str, frequency: str = "", to_date: bool = False, **kw: Any
116
+ ) -> pd.DataFrame:
115
117
  base = (
116
118
  "historical-price-full/"
117
119
  if not frequency
@@ -121,10 +123,14 @@ class FMP(HttpClient):
121
123
  if isinstance(data, dict):
122
124
  data = data.get("historical", [])
123
125
  df = pd.DataFrame(data)
124
- if "date" in df.columns:
126
+ if to_date and "date" in df.columns:
125
127
  df["date"] = pd.to_datetime(df["date"])
126
128
  return df
127
129
 
130
+ # forex
131
+ async def forex_list(self) -> list[dict]:
132
+ return await self.get_path("v3/symbol/available-forex-currency-pairs")
133
+
128
134
  def historical_frequencies(self) -> dict:
129
135
  return {
130
136
  "1min": 1,
@@ -202,6 +202,6 @@ class MarginalDiscrete1D(StochasticProcess1DMarginal):
202
202
  if simpson_rule:
203
203
  result.append(a * simpson(f, x=frequency))
204
204
  else:
205
- result.append(a * np.trapz(f, frequency))
205
+ result.append(a * np.trapezoid(f, frequency))
206
206
  pdf = np.maximum(np.diff(result, prepend=0), 0)
207
207
  return TransformResult(x=x, y=np.cumsum(pdf)) # type: ignore[arg-type]
@@ -0,0 +1,72 @@
1
+ from typing import Self, TypeAlias
2
+
3
+ import numpy as np
4
+ import polars as pl
5
+ import pandas as pd
6
+
7
+
8
+ DataFrame: TypeAlias = pl.DataFrame | pd.DataFrame
9
+
10
+
11
+ def to_polars(df: DataFrame) -> pl.DataFrame:
12
+ if isinstance(df, pd.DataFrame):
13
+ return pl.DataFrame(df)
14
+ return df
15
+
16
+
17
+ class DFutils:
18
+ def __init__(self, df: DataFrame, period: float = 1) -> None:
19
+ self.df = to_polars(df)
20
+ self.period = period
21
+
22
+ def __repr__(self) -> str:
23
+ return repr(self.df)
24
+
25
+ def __str__(self) -> str:
26
+ return str(self.df)
27
+
28
+ def clone(self, df: DataFrame) -> Self:
29
+ return self.__class__(df, self.period)
30
+
31
+ def with_mid(self) -> Self:
32
+ """Adds mid and spread columns to the dataframe"""
33
+ df = self.df
34
+ return self.clone(
35
+ self.df.with_columns(
36
+ mid=0.5 * (df["ask_price"] + df["bid_price"]),
37
+ mid_volume=0.5 * (df["ask_amount"] + df["bid_amount"]),
38
+ spread=20000
39
+ * (df["ask_price"] - df["bid_price"])
40
+ / (df["ask_price"] + df["bid_price"]),
41
+ )
42
+ )
43
+
44
+ def with_parkinson(self) -> Self:
45
+ """Adds parkinson volatility column to the dataframe
46
+
47
+ This requires the high and low columns to be present
48
+ """
49
+ c = 10000 / np.sqrt(4 * self.period * np.log(2))
50
+ return self.clone(
51
+ df=self.df.with_columns(
52
+ pk=c * (pl.col("high") / pl.col("low")).map_elements(np.log)
53
+ )
54
+ )
55
+
56
+ def with_rogers_satchel(self) -> Self:
57
+ """Adds Rogers-Satchel volatility column to the dataframe
58
+
59
+ This requires the high and low columns to be present
60
+ """
61
+ c = 10000 / np.sqrt(self.period)
62
+ return self.clone(
63
+ df=self.df.with_columns(
64
+ rs=c
65
+ * (
66
+ (pl.col("high") / pl.col("open")).map_elements(np.log)
67
+ * (pl.col("high") / pl.col("close")).map_elements(np.log)
68
+ + (pl.col("low") / pl.col("open")).map_elements(np.log)
69
+ * (pl.col("low") / pl.col("close")).map_elements(np.log)
70
+ ).map_elements(np.sqrt)
71
+ )
72
+ )
@@ -183,3 +183,18 @@ def plot3d(
183
183
  if kwargs:
184
184
  fig.update_layout(**kwargs)
185
185
  return fig
186
+
187
+
188
+ def candlestick_plot(df: pd.DataFrame, slider: bool = True) -> Any:
189
+ fig = go.Figure(
190
+ data=go.Candlestick(
191
+ x=df["date"],
192
+ open=df["open"],
193
+ high=df["high"],
194
+ low=df["low"],
195
+ close=df["close"],
196
+ )
197
+ )
198
+ if slider is False:
199
+ fig.update_layout(xaxis_rangeslider_visible=False)
200
+ return fig
@@ -1,14 +1,15 @@
1
1
  from decimal import Decimal
2
2
  from typing import Optional, Union
3
3
 
4
+ import pandas as pd
4
5
  import numpy as np
5
6
  import numpy.typing as npt
6
7
 
7
8
  Number = Decimal
8
9
  Numbers = Union[int, float, np.number]
9
10
  NumberType = Union[float, int, str, Number]
10
- Vector = Union[int, float, complex, np.ndarray]
11
- FloatArray = npt.NDArray[np.float_]
11
+ Vector = Union[int, float, complex, np.ndarray, pd.Series]
12
+ FloatArray = npt.NDArray[np.float64]
12
13
  IntArray = npt.NDArray[np.int_]
13
14
  FloatArrayLike = FloatArray | float
14
15
 
@@ -24,3 +24,9 @@ pip install quantflow
24
24
  * [quantflow.data](https://github.com/quantmind/quantflow/tree/main/quantflow/data) data APIs (requires `quantflow[data]`)
25
25
  * [quantflow.options](https://github.com/quantmind/quantflow/tree/main/quantflow/options) option pricing and calibration
26
26
  * [quantflow.sp](https://github.com/quantmind/quantflow/tree/main/quantflow/sp) stochastic process primitives
27
+
28
+
29
+ ## Command line tools
30
+
31
+ When installing with the extra `data` dependencies, it is possible to use the command line tool `qf`
32
+
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes