Skip to content

Commit

Permalink
Add command line client
Browse files Browse the repository at this point in the history
  • Loading branch information
lsbardel committed Mar 24, 2024
1 parent 7ca05ef commit 6505ab7
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 10 deletions.
2 changes: 1 addition & 1 deletion notebooks/data/fmp.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ jupytext:
extension: .md
format_name: myst
format_version: 0.13
jupytext_version: 1.14.7
jupytext_version: 1.16.1
kernelspec:
display_name: Python 3 (ipykernel)
language: python
Expand Down
32 changes: 32 additions & 0 deletions notebooks/data/timeseries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
jupytext:
text_representation:
extension: .md
format_name: myst
format_version: 0.13
jupytext_version: 1.16.1
kernelspec:
display_name: Python 3 (ipykernel)
language: python
name: python3
---

## Timeseries

```{code-cell} ipython3
from quantflow.data.fmp import FMP
from quantflow.utils.plot import candlestick_plot
cli = FMP()
```

```{code-cell} ipython3
prices = await cli.prices("aapl")
```

```{code-cell} ipython3
candlestick_plot(prices).update_layout(height=500)
```

```{code-cell} ipython3
```
45 changes: 43 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ aiohttp = {version = "^3.8.1", optional = true}
pydantic = "^2.0.2"
pyarrow = "^15.0.0"
ccy = {version="^1.4.0", extras=["cli"]}
asciichart = "^0.1"
python-dotenv = "^1.0.1"
asciichartpy = "^1.5.25"

[tool.poetry.group.dev.dependencies]
black = "^24.1.1"
Expand All @@ -40,11 +43,14 @@ optional = true
jupyter-book = "^1.0.0"
nbconvert = "^7.16.3"
jupytext = "^1.13.8"
plotly = "^5.7.0"
plotly = "^5.20.0"
jupyterlab = "^4.0.2"
sympy = "^1.12"
ipywidgets = "^8.0.7"

[tool.poetry.scripts]
qf = "quantflow.cli:qf"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
Expand Down
58 changes: 58 additions & 0 deletions quantflow/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import asyncio

import click
import dotenv
import pandas as pd
from asciichartpy import plot

from quantflow.data.fmp import FMP

dotenv.load_dotenv()


@click.group()
def qf():
pass


@qf.command()
@click.argument("symbol")
def profile(symbol: str):
"""Company profile"""
data = asyncio.run(get_profile(symbol))[0]
print(data.pop("description"))


@qf.command()
@click.argument("symbol")
@click.option(
"-h",
"--height",
type=int,
default=20,
show_default=True,
help="Chart height",
)
@click.option(
"-l",
"--length",
type=int,
default=100,
show_default=True,
help="Number of data points",
)
def chart(symbol: str, height: int, length: int):
"""Symbol chart"""
df = asyncio.run(get_prices(symbol))
data = df["close"].tolist()
print(plot(data[:length], {"height": height}))


async def get_prices(symbol: str) -> pd.DataFrame:
async with FMP() as cli:
return await cli.prices(symbol)


async def get_profile(symbol: str) -> dict:
async with FMP() as cli:
return await cli.profile(symbol)
4 changes: 2 additions & 2 deletions quantflow/data/client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import json
import os
from dataclasses import dataclass
from typing import Any
from typing import Any, Self

from aiohttp import ClientResponse, ClientSession
from aiohttp.client_exceptions import ContentTypeError
Expand Down Expand Up @@ -52,7 +52,7 @@ async def close(self) -> None:
await self.session.close()
self.session = None

async def __aenter__(self) -> "HttpClient":
async def __aenter__(self) -> Self:
return self

async def __aexit__(self, *args: Any) -> None:
Expand Down
14 changes: 10 additions & 4 deletions quantflow/data/fmp.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os
from dataclasses import dataclass
from dataclasses import dataclass, field
from datetime import date, timedelta
from typing import Any, cast

Expand All @@ -12,7 +12,7 @@
@dataclass
class FMP(HttpClient):
url: str = "https://financialmodelingprep.com/api"
key: str = os.environ.get("FMP_API_KEY", "")
key: str = field(default_factory=lambda: os.environ.get("FMP_API_KEY", ""))

async def stocks(self, **kw: Any) -> list[dict]:
return await self.get_path("v3/stock/list", **kw)
Expand Down Expand Up @@ -111,7 +111,9 @@ async def search(
**self.params(compact(query=query, exchange=exchange, limit=limit), **kw),
)

async def prices(self, ticker: str, frequency: str = "", **kw: Any) -> pd.DataFrame:
async def prices(
self, ticker: str, frequency: str = "", to_date: bool = False, **kw: Any
) -> pd.DataFrame:
base = (
"historical-price-full/"
if not frequency
Expand All @@ -121,10 +123,14 @@ async def prices(self, ticker: str, frequency: str = "", **kw: Any) -> pd.DataFr
if isinstance(data, dict):
data = data.get("historical", [])
df = pd.DataFrame(data)
if "date" in df.columns:
if to_date and "date" in df.columns:
df["date"] = pd.to_datetime(df["date"])
return df

# forex
def forex_list(self) -> list[str]:
return self.get_path("v3/symbol/available-forex-currency-pairs")

def historical_frequencies(self) -> dict:
return {
"1min": 1,
Expand Down
15 changes: 15 additions & 0 deletions quantflow/utils/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,18 @@ def plot3d(
if kwargs:
fig.update_layout(**kwargs)
return fig


def candlestick_plot(df, slider: bool = True) -> Any:
fig = go.Figure(
data=go.Candlestick(
x=df["date"],
open=df["open"],
high=df["high"],
low=df["low"],
close=df["close"],
)
)
if slider is False:
fig.update_layout(xaxis_rangeslider_visible=False)
return fig
8 changes: 8 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,11 @@ pip install quantflow
* [quantflow.data](https://github.com/quantmind/quantflow/tree/main/quantflow/data) data APIs (requires `quantflow[data]`)
* [quantflow.options](https://github.com/quantmind/quantflow/tree/main/quantflow/options) option pricing and calibration
* [quantflow.sp](https://github.com/quantmind/quantflow/tree/main/quantflow/sp) stochastic process primitives


## Command line tools

When installing with the extra `data` dependencies, it is possible to use the command line tool `qf`
```
qf --help
```

0 comments on commit 6505ab7

Please sign in to comment.