Files
OpenBB/gamestonk_terminal/cryptocurrency/cryptocurrency_helpers.py
Didier Rodrigues Lopes a85758c9ec Big UX improvement (#1041)
Co-authored-by: jmaslek <jmaslek11@gmail.com>
Co-authored-by: Chavithra <chavithra@gmail.com>
Co-authored-by: Theodore Aptekarev <aptekarev@gmail.com>
Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com>
Co-authored-by: Didier Rodrigues Lopes <dro.lopes@campus.fct.unl.pt>

* improve user experience phase 1

* add difflib replacement

* implement auto-complete on discovery menu

* auoto-complete, difflib,jump through menus with cd

* Updating tests : terminal

* improve navigation on gst

* add q command to terminal.py

* usage instructions

* Updating tests : terminal

* fix cd command

* vars updated

* show menu when user is going through menus

* allow user to forget the intiail / on scripting

* terminal to accept text file with configuration

* refactor -n to -l and clean code

* add all commands to the tests_stocks_disc

* remove fds from disc since we have search on stocks/ and stocks/sia

* hopefully fix tests

* skip test

* fix completer type and calling menu after command for stocks/disc

* show help menu when moving forward/backwards in menus

* skip test

* skip test - bug fix

* add reset, help and quit to choices

* improve stocks/disc controller

* refactor sia menu

* UX improvements for sia menu

* improve ux design

* refactor ca controller

* fix infinite loop

* improve ux on dps controller

* Add capability of going back from a menu going into a menu

* Ux economy (#1056)

* First round of UX improvements on economy menu

* Do fred menu + sample tests file

* revert to > on menu

* rename jobs file to .gst

* remove cd option

* improve return

* final refactoring of disc_controller

* fix ca,dps,sia,disc,stocks and terminal controllers

* work on ba_controller menu

* fix reset and try_except

* UX on screener controller

* fix for full reset name

* Ux etfs (#1059)

* Refactor ETF menu for new UX

* Add couple more examples to test

* r->reset

* Clean up switch

* gov menu refactored

* fix reset issue

* 80% of refactoring options and pricing/payoff menu is done

* improve payoff controller

* minor fix

* fix: refactor pred and ta stocks controller

* fix: refactor fa(and fmp) controllers

* fix: refactored dd controller (still missing .gst tests)

* fix infinite loop bug

* refactor options controller

* add tests for payoff and pricing

* fix reset for options

* UX Upgrade for Crypto controller(s) (#1049)

* refactor crypto controller

* refactor crypto/defi controller

* added simple test and fixes not returning queue in commands

* Clean up unused functions / iex load (#1047)

* Clean up unused functions and adjust iex load function to not depend on dates

* Had an incorrect tab on s_start definition

* wrong default arg

* regenerate pytest yml

* Comment out parametrization

* Tests : Stocks > Discovery (#1050)

* Updating tests : stocks/discovery/ark

* Updating tests : stocks/discovery/fidelity

* Updating tests : stocks/discovery/fidelity

* Updating tests : stocks/discovery/fidelity

* Updating tests : stocks/discovery/seeking_alpha

* Updating tests : stocks/discovery/seeking_alpha

* Updating tests : stocks/discovery/shortinterest

* Updating tests : stocks/discovery/shortinterest

* Updating tests : stocks/discovery/seeking_alpha

* Updating tests : stocks/discovery/shortinterest

* Updating tests : stocks/discovery/disc_controller

* Updating tests : stocks/dd

* Updating tests : stocks/fa

* Updating tests : stocks/discovery/financedatabase

* Updating tests : stocks/discovery/finnhub

* Updating tests : stocks/discovery/geekofwallstreet

* Updating tests : stocks/discovery/marketbeat

* Updating tests : stocks/discovery/nasdaq

* Updating tests : stocks / discovery / yahoofinance

* Updating tests : black

* Updating tests : unused import

* Updating tests : stocks/discovery/ark

* Tests : Stocks > Doc + Helpers + Government (#1051)

* Updating tests : stocks/government/controller

* Updating tests : stocks/government

* Updating tests : conftest

* Updating tests : stocks > government

* Updating tests : stocks/government

* Updating tests : docs

* Tests : Stocks > Insider (#1054)

* Updating tests : stocks > helper

* Updating tests : doc

* Updating tests : clean stocks > fa > av

* Updating tests : stocks/insider/controller

* Updating tests : stocks/insider/business insider

* Updating tests : stocks/insider/finviz

* Updating tests :  stocks/insider/openinsider

* Updating tests :  stocks/insider/controller

* Updating tests : black

* Updating tests : stocks/insider/controller

* Tests : Stocks > Backtesting + Behavioural Analysis  (#1057)

* Updating tests : add __init__ files

* Updating tests : stocsk/behavioural_analysis

* Updating tests : black

* Updating tests : stocks/backtesting

* Updating tests : stocks/backtesting

* fix: converted top to limit arguments

* fix: refactor disc controller, updated docs

* fix: refactor dd_controller and docs

* fix: refactor nft controller and docs

* fix: pass test temporarily, onchain controller refactor, docs

* fix: overview controller refactor, fix quit command

* fix: linting issues

* fix: refacot ta controller

* fix: refactor pred controller

* fix: linting

* fix: crypto controller

* fix: added tests, updated all controlers

* fix: menu print renamed from stocks to crypto controller, added tests

* fix: fix faster function execution

* Fix annoying pylint C0201 error

* fix: renamed commands to long format

* DISC Cleanup (#1058)

* Get rid/cleanup of marketbeat functions

* Get rid of last unused disc function + fix related tests

* fix test

* Dividend History Chart (#1053)

* Dividend History Chart

* changed to default number 10

* changed divs flag default to false

* updating the expected result for test_fa_controller.

* else statement

* fix: added load on dd

* fix: added autocompletion in all commands with argument choices

* fix: linting

* Workflows + Stocks > Insider (#1061)

* Updating code : stocks/insider remove unused file

* Updating workflows : tests - set mypy==0.910

* fix: linting

* Fixing Linting (#1062)

* Updating code : fixing linting

mypy message = Too many arguments for <lambda>

* Updating workflows : allow newest mypy version

* Updating code : apply black

* Updating code : black

* fix: updated predict controller help to match stocks

* Ux: portfolio (#1063)

* First step of portfolio UX

* Add all broker controllers to UX stuff

* UX Improvement for PO

Co-authored-by: Didier Rodrigues Lopes <dro.lopes@campus.fct.unl.pt>

* UX Improvement for resources (#1064)

Co-authored-by: Didier Rodrigues Lopes <dro.lopes@campus.fct.unl.pt>

* UX: stock/bt (#1065)

* UX: stocks>qa (#1068)

* fix mypy lambda

* skip tests for now

* remove unused paths.py

* rename tests/simulator to tests/e2e

* refactor options/screener menu

* UX : move `gst` files location

* fix stocks_controller

* UX upgrade of the Forex menu (#1048)

* Add basic forex menu test

* Add forex routes to terminal paths

* Remove commands from paths because they're not menus

* WIP Refactor forex controller

* refactor crypto controller

* Remove commented code

* Improve user output with printed text

* Add "help" back to the list of choices

* Enable the command queue for the forex controller

* refactor crypto/defi controller

* Fix candle chart blocking the terminal

* Black

* Return help and reset to the list of known args

* added simple test and fixes not returning queue in commands

* Add currency codes loading to the av_model

* Return the queue in edge cases (when commands don't process)

* Split select into to and from to enable autocompletion

* Style text output

* Stop printing help after the execution of every command

* Update test scenarios

* Black

* fix: converted top to limit arguments

* fix: refactor disc controller, updated docs

* Delete oanda the old view file that was moved into the oanda menu

* fix: refactor dd_controller and docs

* fix: refactor nft controller and docs

* fix: pass test temporarily, onchain controller refactor, docs

* fix: overview controller refactor, fix quit command

* fix: linting issues

* fix: refacot ta controller

* fix: refactor pred controller

* fix: linting

* fix: crypto controller

* fix: added tests, updated all controlers

* fix: menu print renamed from stocks to crypto controller, added tests

* fix: fix faster function execution

* Implement basic UX improvement of the oanda controller

* Update the forex controller

* Fix annoying pylint C0201 error

* Add latest convention changes to the forex controller

* fix: renamed commands to long format

* fix: added load on dd

* Merge the latest updates of the controller design

* fix: added autocompletion in all commands with argument choices

* fix: linting

* fix: linting

* fix: updated predict controller help to match stocks

* Update the forex menu e2e test scripts

* Add check_non_negative_float helper

* Update the controller with the latest changes to the convention

* Update the currency pair loading mechanism

* Move data models logic to the models file

* Update update oanda views to be interact with the models

* Upgrade oanda controller

* Remove raw stocks ba and eda code from the forex menu

* Update "help wanted" banner for ba and eda in forex menu

* Remove remainders of stocks ba and eda from forex context

* Improve typing, docstrings and error messages

* Remove stocks ba and eda code that was merged from other ux branches

* Add fixes that prevented incorrect argument handling

* Remove -argument from the candles call
If there is an expected agr `-g` and you put an incorrect argument
`-argument` the difflib will interpret `argument` as `g`

Co-authored-by: jose-donato <zmcdonato@gmail.com>
Co-authored-by: Didier Rodrigues Lopes <dro.lopes@campus.fct.unl.pt>

* fix reset for menus that require ticker

* UX improvement on research menu

* skip insider controller test

* initial refactoring of insider_controller

* improve insider controller ux part 2

* finish refactoring ins controller ux menu

* fix bug of when commands in queue have args

* skip test

* comment test stuff

* UX: stocks>qa (#1071)

* refactor return self.queue

* fix return None

* minor fix

* minor tabulate fix

* Get rid of leading '/' in terminal and add some newlines on quits. (#1074)

* Get rid of leading '/' in terminal and add some newlines on quits.

* print crypto help on menu entry

* looks like a format issue here...

* newlines on quit

* remove unnecessary line break

* fix pylint issue

* refactor

* refactor

* allow portfolio optimization to quit context

* add exit at end of scripts

* improve dd_controller

* test ux in stocks/dd menu

* Ux upgrade for reports context (#1075)

* Refactor reports and upgrade them with the latest controller convention

* Add test scenarios for the reports context

* test ux stocks/ta

* ux branch scripts/ta

* improvement on main param

* Upgrades for the UX upgrade for the fa and fa/fmp menus (#1076)

* Change --num to --limit

* Remove inconsistent/unreliable functions from the choices list

* Improve docstring compliance with numpy doc format

* Fix hardcoded class id in dcf scrapper

* Fix annoying pylint error in discordbot that was blocking the hook

* Add test scenarios for the fa and fa/fmp menus

* Fix forgotten replacement of --num to --limit

* Fix tests

* Return some excluded commands to the choices list

* Fix dd report to reflect the updates

* Fix set function not returning the queue

* Update gst test files

* fix exit on ca from another submenu

* fix changes of options/screener

* fix dps controller

* fix fa when running out of AV calls

* Fix TVL plot locking interpreter during defi test

* Add exception handling for broken coingecko scrapper

* skip fa/av test that fails

* fix dps tests

Co-authored-by: Chavithra PARANA <chavithra@gmail.com>
Co-authored-by: jmaslek <jmaslek11@gmail.com>
Co-authored-by: jose-donato <zmcdonato@gmail.com>
Co-authored-by: jose-donato <43375532+jose-donato@users.noreply.github.com>
Co-authored-by: Theodore Aptekarev <aptekarev@gmail.com>
Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com>
2021-12-21 15:19:23 +03:00

850 lines
26 KiB
Python

"""Cryptocurrency helpers"""
__docformat__ = "numpy"
import os
import json
from typing import Tuple, Any, Optional, Union
import difflib
import pandas as pd
import numpy as np
from binance.client import Client
import matplotlib.pyplot as plt
from tabulate import tabulate
import mplfinance as mpf
from pycoingecko import CoinGeckoAPI
from gamestonk_terminal.helper_funcs import (
plot_autoscale,
export_data,
)
from gamestonk_terminal.config_plot import PLOT_DPI
from gamestonk_terminal.cryptocurrency.due_diligence import (
pycoingecko_model,
coinpaprika_model,
)
from gamestonk_terminal.cryptocurrency.discovery.pycoingecko_model import get_coin_list
from gamestonk_terminal.cryptocurrency.overview.coinpaprika_model import (
get_list_of_coins,
)
from gamestonk_terminal.cryptocurrency.due_diligence.binance_model import (
check_valid_binance_str,
show_available_pairs_for_given_symbol,
plot_candles,
)
from gamestonk_terminal.cryptocurrency.due_diligence import coinbase_model
import gamestonk_terminal.config_terminal as cfg
from gamestonk_terminal.feature_flags import USE_ION as ion
from gamestonk_terminal import feature_flags as gtff
# TODO: Improve implementation of coin loading
# Currently adding this function to helpers for implementing prediction menu
INTERVALS = ["1H", "3H", "6H", "1D"]
def load_cg_coin_data(
coin: str, currency: str = "USD", days: int = 365, sampling: str = "1D"
) -> pd.DataFrame:
"""Load cryptocurrency data from CoinGecko
Timestamps from CoinGecko are not uniform, so the sampling is included to provide ohlc bars.
Note that for days > 90, daily data is returned as prices only. Less than 90 days returns hourly data
which can be consolidated into OHLC
Parameters
----------
coin : str
Cryptocurrency to load
currency : str, optional
Conversion unit, by default "USD"
days : int, optional
Number of days to get, by default 365
sampling : str, optional
Time period to resample in the format in the format #U where U can be H (hour) or D(day), by default "1D"
Returns
-------
pd.DataFrame
DataFrame of OHLC
"""
prices = CoinGeckoAPI().get_coin_market_chart_by_id(coin, currency, days)
df = pd.DataFrame(data=prices["prices"], columns=["time", "price"])
df["time"] = pd.to_datetime(df.time, unit="ms")
df = df.set_index("time")
if days > 90:
sampling = "1D"
df = df.resample(sampling).ohlc()
df.columns = ["Open", "High", "Low", "Close"]
return df
def _load_coin_map(file_name: str) -> pd.DataFrame:
if file_name.split(".")[1] != "json":
raise TypeError("Please load json file")
current_dir = os.path.dirname(os.path.abspath(__file__))
path = os.path.join(current_dir, "data", file_name)
with open(path, encoding="utf8") as f:
coins = json.load(f)
coins_df = pd.Series(coins).reset_index()
coins_df.columns = ["symbol", "id"]
return coins_df
def load_binance_map():
return _load_coin_map("binance_gecko_map.json")
def load_coinbase_map():
return _load_coin_map("coinbase_gecko_map.json")
def prepare_all_coins_df() -> pd.DataFrame:
"""Helper method which loads coins from all sources: CoinGecko, CoinPaprika, Binance
and merge those coins on keys:
CoinGecko - > name < - CoinPaprika
CoinGecko - > id <- Binance
Returns
-------
pd.DataFrame
CoinGecko - id for coin in CoinGecko API: uniswap
CoinPaprika - id for coin in CoinPaprika API: uni-uniswap
Binance - symbol (baseAsset) for coin in Binance API: UNI
Coinbase - symbol for coin in Coinbase Pro API e.g UNI
Symbol: uni
"""
gecko_coins_df = get_coin_list()
paprika_coins_df = get_list_of_coins()
# TODO: Think about scheduled job, that once a day will update data
binance_coins_df = load_binance_map().rename(columns={"symbol": "Binance"})
coinbase_coins_df = load_coinbase_map().rename(columns={"symbol": "Coinbase"})
gecko_paprika_coins_df = pd.merge(
gecko_coins_df, paprika_coins_df, on="name", how="left"
)
df_merged = pd.merge(
left=gecko_paprika_coins_df,
right=binance_coins_df,
left_on="id_x",
right_on="id",
how="left",
)
df_merged.rename(
columns={
"id_x": "CoinGecko",
"symbol_x": "Symbol",
"id_y": "CoinPaprika",
},
inplace=True,
)
df_merged = pd.merge(
left=df_merged,
right=coinbase_coins_df,
left_on="CoinGecko",
right_on="id",
how="left",
)
return df_merged[["CoinGecko", "CoinPaprika", "Binance", "Coinbase", "Symbol"]]
def _create_closest_match_df(
coin: str, coins: pd.DataFrame, limit: int, cutoff: float
) -> pd.DataFrame:
"""Helper method. Creates a DataFrame with best matches for given coin found in given list of coins.
Based on difflib.get_close_matches func.
Parameters
----------
coin: str
coin you search for
coins: list
list of coins in which you want to find similarities
limit: int
limit of matches
cutoff: float
float between <0, 1>. Show only coins matches with score higher then cutoff.
Returns
-------
pd.DataFrame
index, id, name, symbol - > depends on source of data.
"""
coins_list = coins["id"].to_list()
sim = difflib.get_close_matches(coin, coins_list, limit, cutoff)
df = pd.Series(sim).to_frame().reset_index()
df.columns = ["index", "id"]
return df.merge(coins, on="id")
def load(
coin: str,
source: str,
) -> Tuple[Union[Optional[str], pycoingecko_model.Coin], Optional[Any], Optional[Any]]:
"""Load cryptocurrency from given source. Available sources are: CoinGecko, CoinPaprika, Coinbase and Binance.
Loading coin from Binance and CoinPaprika means validation if given coins exists in chosen source,
if yes then id of the coin is returned as a string.
In case of CoinGecko load will return Coin object, if provided coin exists. Coin object has access to different coin
information.
Parameters
----------
coin: str
Coin symbol or id which is checked if exists in chosen data source.
source : str
Source of the loaded data. CoinGecko, CoinPaprika, or Binance
Returns
-------
Tuple[Union[str, pycoingecko_model.Coin], str, str]
- str or Coin object for provided coin
- str with source of the loaded data. CoinGecko, CoinPaprika, or Binance
- str with symbol
"""
current_coin = "" # type: Optional[Any]
if source == "cg":
coingecko = pycoingecko_model.Coin(coin)
return coingecko, source, coingecko.symbol
if source == "bin":
parsed_coin = coin.upper()
current_coin, pairs = show_available_pairs_for_given_symbol(parsed_coin)
if len(pairs) > 0:
print(f"Coin found : {current_coin}\n")
else:
print(f"Couldn't find coin with symbol {current_coin}\n")
return current_coin, source, parsed_coin
if source == "cp":
paprika_coins = get_list_of_coins()
paprika_coins_dict = dict(zip(paprika_coins.id, paprika_coins.symbol))
current_coin, symbol = coinpaprika_model.validate_coin(coin, paprika_coins_dict)
return current_coin, source, symbol
if source == "cb":
coinbase_coin = coin.upper()
current_coin, pairs = coinbase_model.show_available_pairs_for_given_symbol(
coinbase_coin
)
if len(pairs) > 0:
print(f"Coin found : {current_coin}\n")
else:
print(f"Couldn't find coin with symbol {current_coin}\n")
return current_coin, source, coin
return current_coin, None, None
FIND_KEYS = ["id", "symbol", "name"]
# TODO: Find better algorithm then difflib.get_close_matches to find most similar coins
def find(source: str, coin: str, key: str, top: int, export: str) -> None:
"""Find similar coin by coin name,symbol or id.
If you don't remember exact name or id of the Coin at CoinGecko CoinPaprika, Binance or Coinbase
you can use this command to display coins with similar name, symbol or id to your search query.
Example of usage: coin name is something like "polka". So I can try: find -c polka -k name -t 25
It will search for coin that has similar name to polka and display top 25 matches.
-c, --coin stands for coin - you provide here your search query
-k, --key it's a searching key. You can search by symbol, id or name of coin
-t, --top it displays top N number of records.
Parameters
----------
top: int
Number of records to display
coin: str
Cryptocurrency
key: str
Searching key (symbol, id, name)
source: str
Data source of coins. CoinGecko (cg) or CoinPaprika (cp) or Binance (bin), Coinbase (cb)
export : str
Export dataframe data to csv,json,xlsx file
"""
if source == "cg":
coins_df = get_coin_list()
coins_list = coins_df[key].to_list()
if key in ["symbol", "id"]:
coin = coin.lower()
sim = difflib.get_close_matches(coin, coins_list, top)
df = pd.Series(sim).to_frame().reset_index()
df.columns = ["index", key]
coins_df.drop("index", axis=1, inplace=True)
df = df.merge(coins_df, on=key)
elif source == "cp":
coins_df = get_list_of_coins()
coins_list = coins_df[key].to_list()
keys = {"name": "title", "symbol": "upper", "id": "lower"}
func_key = keys[key]
coin = getattr(coin, str(func_key))()
sim = difflib.get_close_matches(coin, coins_list, top)
df = pd.Series(sim).to_frame().reset_index()
df.columns = ["index", key]
df = df.merge(coins_df, on=key)
elif source == "bin":
# TODO: Fix it in future. Determine if user looks for symbol like ETH or ethereum
if len(coin) > 5:
key = "id"
coins_df_gecko = get_coin_list()
coins_df_bin = load_binance_map()
coins = pd.merge(
coins_df_bin, coins_df_gecko[["id", "name"]], how="left", on="id"
)
coins_list = coins[key].to_list()
sim = difflib.get_close_matches(coin, coins_list, top)
df = pd.Series(sim).to_frame().reset_index()
df.columns = ["index", key]
df = df.merge(coins, on=key)
elif source == "cb":
if len(coin) > 5:
key = "id"
coins_df_gecko = get_coin_list()
coins_df_bin = load_coinbase_map()
coins = pd.merge(
coins_df_bin, coins_df_gecko[["id", "name"]], how="left", on="id"
)
coins_list = coins[key].to_list()
sim = difflib.get_close_matches(coin, coins_list, top)
df = pd.Series(sim).to_frame().reset_index()
df.columns = ["index", key]
df = df.merge(coins, on=key)
else:
print(
"Couldn't execute find methods for CoinPaprika, Binance, Coinbase or CoinGecko\n"
)
df = pd.DataFrame()
if gtff.USE_TABULATE_DF:
print(
tabulate(
df,
headers=df.columns,
floatfmt=".1f",
showindex=False,
tablefmt="fancy_grid",
),
"\n",
)
else:
print(df.to_string, "\n")
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"find",
df,
)
def display_all_coins(
source: str, coin: str, top: int, skip: int, show_all: bool, export: str
) -> None:
"""Find similar coin by coin name,symbol or id.
If you don't remember exact name or id of the Coin at CoinGecko, CoinPaprika, Coinbase, Binance
you can use this command to display coins with similar name, symbol or id to your search query.
Example of usage: coin name is something like "polka". So I can try: find -c polka -k name -t 25
It will search for coin that has similar name to polka and display top 25 matches.
-c, --coin stands for coin - you provide here your search query
-t, --top it displays top N number of records.
Parameters
----------
top: int
Number of records to display
coin: str
Cryptocurrency
source: str
Data source of coins. CoinGecko (cg) or CoinPaprika (cp) or Binance (bin), Coinbase (cb)
skip: int
Skip N number of records
show_all: bool
Flag to show all sources of data
export : str
Export dataframe data to csv,json,xlsx file
"""
sources = ["cg", "cp", "bin", "cb"]
limit, cutoff = 30, 0.75
coins_func_map = {
"cg": get_coin_list,
"cp": get_list_of_coins,
"bin": load_binance_map,
"cb": load_coinbase_map,
}
if show_all:
coins_func = coins_func_map.get(source)
if coins_func:
df = coins_func()
else:
df = prepare_all_coins_df()
elif not source or source not in sources:
df = prepare_all_coins_df()
cg_coins_list = df["CoinGecko"].to_list()
sim = difflib.get_close_matches(coin.lower(), cg_coins_list, limit, cutoff)
df_matched = pd.Series(sim).to_frame().reset_index()
df_matched.columns = ["index", "CoinGecko"]
df = df.merge(df_matched, on="CoinGecko")
df.drop("index", axis=1, inplace=True)
else:
if source == "cg":
coins_df = get_coin_list().drop("index", axis=1)
df = _create_closest_match_df(coin.lower(), coins_df, limit, cutoff)
df = df[["index", "id", "name"]]
elif source == "cp":
coins_df = get_list_of_coins()
df = _create_closest_match_df(coin.lower(), coins_df, limit, cutoff)
df = df[["index", "id", "name"]]
elif source == "bin":
coins_df_gecko = get_coin_list()
coins_df_bin = load_binance_map()
coins_df_bin.columns = ["symbol", "id"]
coins_df = pd.merge(
coins_df_bin, coins_df_gecko[["id", "name"]], how="left", on="id"
)
df = _create_closest_match_df(coin.lower(), coins_df, limit, cutoff)
df = df[["index", "symbol", "name"]]
df.columns = ["index", "id", "name"]
elif source == "cb":
coins_df_gecko = get_coin_list()
coins_df_cb = load_coinbase_map()
coins_df_cb.columns = ["symbol", "id"]
coins_df = pd.merge(
coins_df_cb, coins_df_gecko[["id", "name"]], how="left", on="id"
)
df = _create_closest_match_df(coin.lower(), coins_df, limit, cutoff)
df = df[["index", "symbol", "name"]]
df.columns = ["index", "id", "name"]
else:
df = pd.DataFrame(columns=["index", "id", "symbol"])
print("Couldn't find any coins")
print("")
try:
df = df[skip : skip + top]
except Exception as e:
print(e)
if gtff.USE_TABULATE_DF:
print(
tabulate(
df,
headers=df.columns,
floatfmt=".1f",
showindex=False,
tablefmt="fancy_grid",
)
)
else:
print(df.to_string, "\n")
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"coins",
df,
)
def load_ta_data(
coin: Union[str, pycoingecko_model.Coin], source: str, currency: str, **kwargs: Any
) -> Tuple[pd.DataFrame, str]:
"""Load data for Technical Analysis
Parameters
----------
coin: str
Cryptocurrency
source: str
Source of data: CoinGecko, Binance, CoinPaprika
currency: str
Quotes currency
kwargs:
days: int
Days limit for coingecko, coinpaprika
limit: int
Limit for binance quotes
interval: str
Time interval for Binance
Returns
----------
Tuple[pd.DataFrame, str]
df with prices
quoted currency
"""
limit = kwargs.get("limit", 100)
interval = kwargs.get("interval", "1day")
days = kwargs.get("days", 30)
if source == "bin":
client = Client(cfg.API_BINANCE_KEY, cfg.API_BINANCE_SECRET)
interval_map = {
"1day": client.KLINE_INTERVAL_1DAY,
"3day": client.KLINE_INTERVAL_3DAY,
"1hour": client.KLINE_INTERVAL_1HOUR,
"2hour": client.KLINE_INTERVAL_2HOUR,
"4hour": client.KLINE_INTERVAL_4HOUR,
"6hour": client.KLINE_INTERVAL_6HOUR,
"8hour": client.KLINE_INTERVAL_8HOUR,
"12hour": client.KLINE_INTERVAL_12HOUR,
"1week": client.KLINE_INTERVAL_1WEEK,
"1min": client.KLINE_INTERVAL_1MINUTE,
"3min": client.KLINE_INTERVAL_3MINUTE,
"5min": client.KLINE_INTERVAL_5MINUTE,
"15min": client.KLINE_INTERVAL_15MINUTE,
"30min": client.KLINE_INTERVAL_30MINUTE,
"1month": client.KLINE_INTERVAL_1MONTH,
}
assert isinstance(coin, str)
pair = coin + currency
if check_valid_binance_str(pair):
print(f"{coin} loaded vs {currency.upper()}")
candles = client.get_klines(
symbol=pair,
interval=interval_map[interval],
limit=limit,
)
candles_df = pd.DataFrame(candles).astype(float).iloc[:, :6]
candles_df.columns = [
"date",
"Open",
"High",
"Low",
"Close",
"Volume",
]
df_coin = candles_df.set_index(
pd.to_datetime(candles_df["date"], unit="ms")
).drop("date", axis=1)
return df_coin, currency
return pd.DataFrame(), currency
if source == "cp":
df = coinpaprika_model.get_ohlc_historical(str(coin), currency.upper(), days)
if df.empty:
print("No data found", "\n")
return pd.DataFrame(), ""
df.drop(["time_close", "market_cap"], axis=1, inplace=True)
df.columns = [
"date",
"Open",
"High",
"Low",
"Close",
"Volume",
]
df = df.set_index(pd.to_datetime(df["date"])).drop("date", axis=1)
return df, currency
if source == "cg":
assert isinstance(coin, pycoingecko_model.Coin)
df = coin.get_coin_market_chart(currency, days)
df = df["price"].resample("1D").ohlc().ffill()
df.columns = [
"Open",
"High",
"Low",
"Close",
]
df.index.name = "date"
return df, currency
if source == "cb":
assert isinstance(coin, str)
coin, currency = coin.upper(), currency.upper()
pair = f"{coin}-{currency}"
if coinbase_model.check_validity_of_product(pair):
print(f"{coin} loaded vs {currency}")
df = coinbase_model.get_candles(
product_id=pair,
interval=interval or "24hour",
).head(limit)
df_coin = df.set_index(pd.to_datetime(df["date"], unit="s")).drop(
"date", axis=1
)
return df_coin[::-1], currency
return pd.DataFrame(), currency
def plot_chart(
coin: Union[str, pycoingecko_model.Coin], source: str, currency: str, **kwargs: Any
) -> None:
"""Load data for Technical Analysis
Parameters
----------
coin: str
Cryptocurrency
source: str
Source of data: CoinGecko, Binance, CoinPaprika
currency: str
Quotes currency
kwargs:
days: int
Days limit for coingecko, coinpaprika
limit: int
Limit for binance quotes
interval: str
Time interval for Binance
Returns
----------
Tuple[pd.DataFrame, str]
dataframe with prices
quoted currency
"""
limit = kwargs.get("limit", 100)
interval = kwargs.get("interval", "1day")
days = kwargs.get("days", 30)
if source == "bin":
client = Client(cfg.API_BINANCE_KEY, cfg.API_BINANCE_SECRET)
interval_map = {
"1day": client.KLINE_INTERVAL_1DAY,
"3day": client.KLINE_INTERVAL_3DAY,
"1hour": client.KLINE_INTERVAL_1HOUR,
"2hour": client.KLINE_INTERVAL_2HOUR,
"4hour": client.KLINE_INTERVAL_4HOUR,
"6hour": client.KLINE_INTERVAL_6HOUR,
"8hour": client.KLINE_INTERVAL_8HOUR,
"12hour": client.KLINE_INTERVAL_12HOUR,
"1week": client.KLINE_INTERVAL_1WEEK,
"1min": client.KLINE_INTERVAL_1MINUTE,
"3min": client.KLINE_INTERVAL_3MINUTE,
"5min": client.KLINE_INTERVAL_5MINUTE,
"15min": client.KLINE_INTERVAL_15MINUTE,
"30min": client.KLINE_INTERVAL_30MINUTE,
"1month": client.KLINE_INTERVAL_1MONTH,
}
assert isinstance(coin, str)
pair = coin + currency
if check_valid_binance_str(pair):
print(f"{coin} loaded vs {currency.upper()}")
candles = client.get_klines(
symbol=pair,
interval=interval_map[interval],
limit=limit,
)
candles_df = pd.DataFrame(candles).astype(float).iloc[:, :6]
candles_df.columns = [
"date",
"Open",
"High",
"Low",
"Close",
"Volume",
]
df_coin = candles_df.set_index(
pd.to_datetime(candles_df["date"], unit="ms")
).drop("date", axis=1)
plot_candles(
df_coin,
f"{coin + currency} from {df_coin.index[0].strftime('%Y/%m/%d')} to "
f"{df_coin.index[-1].strftime('%Y/%m/%d')}",
)
if source == "cp":
df = coinpaprika_model.get_ohlc_historical(str(coin), currency.upper(), days)
if df.empty:
print("There is not data to plot chart\n")
return
df.drop(["time_close", "market_cap"], axis=1, inplace=True)
df.columns = [
"date",
"Open",
"High",
"Low",
"Close",
"Volume",
]
df = df.set_index(pd.to_datetime(df["date"])).drop("date", axis=1)
title = (
f"\n{coin}/{currency} from {df.index[0].strftime('%Y/%m/%d')} to {df.index[-1].strftime('%Y/%m/%d')}",
)
df["Volume"] = df["Volume"] / 1_000_000
mpf.plot(
df,
type="candle",
volume=True,
ylabel_lower="Volume [1M]",
title=str(title[0]) if isinstance(title, tuple) else title,
xrotation=20,
style="binance",
figratio=(10, 7),
figscale=1.10,
figsize=(plot_autoscale()),
update_width_config=dict(
candle_linewidth=1.0, candle_width=0.8, volume_linewidth=1.0
),
)
if ion:
plt.ion()
plt.show()
print("")
if source == "cg":
assert isinstance(coin, pycoingecko_model.Coin)
df = coin.get_coin_market_chart(currency, days)
df = df["price"].resample("1D").ohlc().ffill()
df.columns = [
"Open",
"High",
"Low",
"Close",
]
title = (
f"\n{coin.coin_symbol}/{currency} from {df.index[0].strftime('%Y/%m/%d')} "
f"to {df.index[-1].strftime('%Y/%m/%d')}",
)
mpf.plot(
df,
type="candle",
volume=False,
title=str(title[0]) if isinstance(title, tuple) else title,
xrotation=20,
style="binance",
figratio=(10, 7),
figscale=1.10,
figsize=(plot_autoscale()),
update_width_config=dict(
candle_linewidth=1.0, candle_width=0.8, volume_linewidth=1.0
),
)
if ion:
plt.ion()
plt.show()
print("")
if source == "cb":
assert isinstance(coin, str)
coin, currency = coin.upper(), currency.upper()
pair = f"{coin}-{currency}"
if coinbase_model.check_validity_of_product(pair):
print(f"{coin} loaded vs {currency}")
df = coinbase_model.get_candles(
product_id=pair,
interval=interval or "24hour",
).head(limit)
df = df.astype(float).iloc[:, :6]
df.sort_values(by="date", inplace=True, ascending=True)
df = df.set_index(pd.to_datetime(df["date"], unit="s")).drop("date", axis=1)
title = (
f"\n{coin}/{currency} from {df.index[0].strftime('%Y/%m/%d')} to {df.index[-1].strftime('%Y/%m/%d')}",
)
df["Volume"] = df["Volume"] / 1_000
mpf.plot(
df,
type="candle",
volume=True,
ylabel_lower="Volume [1K]",
title=str(title[0]) if isinstance(title, tuple) else title,
xrotation=20,
style="binance",
figratio=(10, 7),
figscale=1.10,
figsize=(plot_autoscale()),
update_width_config=dict(
candle_linewidth=1.0, candle_width=0.8, volume_linewidth=1.0
),
)
if ion:
plt.ion()
plt.show()
print("")
def plot_order_book(bids: np.ndarray, asks: np.ndarray, coin: str) -> None:
"""
Plots Bid/Ask. Can be used for Coinbase and Binance
Parameters
----------
bids : np.array
array of bids with columns: price, size, cumulative size
asks : np.array
array of asks with columns: price, size, cumulative size
coin : str
Coin being plotted
"""
_, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
ax.plot(bids[:, 0], bids[:, 2], "g", label="bids")
ax.fill_between(bids[:, 0], bids[:, 2], color="g", alpha=0.4)
ax.plot(asks[:, 0], asks[:, 2], "r", label="asks")
ax.fill_between(asks[:, 0], asks[:, 2], color="r", alpha=0.4)
plt.grid(b=True, which="major", color="#666666", linestyle="-")
plt.minorticks_on()
plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
plt.legend(loc=0)
plt.xlabel("Price")
plt.ylabel("Size (Coins) ")
plt.title(f"Order Book for {coin}")
if ion:
plt.ion()
plt.show()
print("")