-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from quantmind/ls-deribit
Add command line client
- Loading branch information
Showing
14 changed files
with
1,545 additions
and
1,242 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
--- | ||
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("ethusd", frequency="") | ||
``` | ||
|
||
```{code-cell} ipython3 | ||
candlestick_plot(prices).update_layout(height=500) | ||
``` | ||
|
||
```{code-cell} ipython3 | ||
from quantflow.utils.df import DFutils | ||
df = DFutils(prices).with_rogers_satchel().with_parkinson() | ||
df | ||
``` | ||
|
||
```{code-cell} ipython3 | ||
``` |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import asyncio | ||
import os | ||
from dataclasses import dataclass, field | ||
from typing import Any | ||
|
||
import click | ||
import dotenv | ||
import pandas as pd | ||
from asciichartpy import plot | ||
from ccy.cli.console import df_to_rich | ||
from prompt_toolkit import PromptSession | ||
from prompt_toolkit.history import FileHistory | ||
from rich.console import Console | ||
from rich.text import Text | ||
|
||
from quantflow.data.fmp import FMP | ||
|
||
from . import settings | ||
|
||
dotenv.load_dotenv() | ||
|
||
FREQUENCIES = tuple(FMP().historical_frequencies()) | ||
|
||
|
||
@click.group() | ||
def qf() -> None: | ||
pass | ||
|
||
|
||
@qf.command() | ||
@click.argument("symbol") | ||
def profile(symbol: str) -> None: | ||
"""Company profile""" | ||
data = asyncio.run(get_profile(symbol))[0] | ||
main.print(data.pop("description")) | ||
df = pd.DataFrame(data.items(), columns=["Key", "Value"]) | ||
main.print(df_to_rich(df)) | ||
|
||
|
||
@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", | ||
) | ||
@click.option( | ||
"-f", | ||
"--frequency", | ||
type=click.Choice(FREQUENCIES), | ||
default="", | ||
help="Number of data points", | ||
) | ||
def chart(symbol: str, height: int, length: int, frequency: str) -> None: | ||
"""Symbol chart""" | ||
df = asyncio.run(get_prices(symbol, frequency)) | ||
data = list(reversed(df["close"].tolist()[:length])) | ||
print(plot(data, {"height": height})) | ||
|
||
|
||
async def get_prices(symbol: str, frequency: str) -> pd.DataFrame: | ||
async with FMP() as cli: | ||
return await cli.prices(symbol, frequency) | ||
|
||
|
||
async def get_profile(symbol: str) -> list[dict]: | ||
async with FMP() as cli: | ||
return await cli.profile(symbol) | ||
|
||
|
||
@dataclass | ||
class App: | ||
console: Console = field(default_factory=Console) | ||
|
||
def __call__(self) -> None: | ||
os.makedirs(settings.SETTINGS_DIRECTORY, exist_ok=True) | ||
history = FileHistory(str(settings.HIST_FILE_PATH)) | ||
session: PromptSession = PromptSession(history=history) | ||
|
||
self.print("Welcome to QuantFlow!", style="bold green") | ||
self.handle_command("help") | ||
|
||
try: | ||
while True: | ||
try: | ||
text = session.prompt("quantflow> ") | ||
except KeyboardInterrupt: | ||
break | ||
else: | ||
self.handle_command(text) | ||
except click.Abort: | ||
self.console.print(Text("Bye!", style="bold magenta")) | ||
|
||
def print(self, text_alike: Any, style: str = "") -> None: | ||
if isinstance(text_alike, str): | ||
style = style or "cyan" | ||
text_alike = Text(f"\n{text_alike}\n", style="cyan") | ||
self.console.print(text_alike) | ||
|
||
def error(self, err: str | Exception) -> None: | ||
self.console.print(Text(f"\n{err}\n", style="bold red")) | ||
|
||
def handle_command(self, text: str) -> None: | ||
self.current_command = text.split(" ")[0].strip() | ||
if not text: | ||
return | ||
elif text == "help": | ||
return qf.main(["--help"], standalone_mode=False) | ||
elif text == "exit": | ||
raise click.Abort() | ||
|
||
try: | ||
qf.main(text.split(), standalone_mode=False) | ||
except click.exceptions.MissingParameter as e: | ||
self.error(e) | ||
except click.exceptions.NoSuchOption as e: | ||
self.error(e) | ||
|
||
|
||
main = App() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# IMPORTATION STANDARD | ||
from pathlib import Path | ||
|
||
# Installation related paths | ||
HOME_DIRECTORY = Path.home() | ||
PACKAGE_DIRECTORY = Path(__file__).parent.parent.parent | ||
REPOSITORY_DIRECTORY = PACKAGE_DIRECTORY.parent | ||
|
||
SETTINGS_DIRECTORY = HOME_DIRECTORY / ".quantflow" | ||
SETTINGS_ENV_FILE = SETTINGS_DIRECTORY / ".env" | ||
HIST_FILE_PATH = SETTINGS_DIRECTORY / ".quantflow.his" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.