Files
OpenBB/openbb_terminal/cryptocurrency/defi/graph_model.py
teh_coderer 59d8b36bb0 [IMPROVE] Fix Docstring formatting/Fix missing, incomplete type hints (#3412)
* Fixes

* Update stocks_helper.py

* update git-actions set-output to new format

* Update stocks_helper.py

* Update terminal_helper.py

* removed LineAnnotateDrawer from qa_view

* lint

* few changes

* updates

* sdk auto gen modules done

* Update stocks_helper.py

* updates to changed imports, and remove first sdk_modules

* Update generate_sdk.py

* Update generate_sdk.py

* pylint

* revert stocks_helper

* Update generate_sdk.py

* Update sdk.py

* Update generate_sdk.py

* full auto generation, added sdk.py/controllers creation

* missed enable forecasting

* added running black in subprocess after sdk files generation completes

* removed deleted sdk_arg_logger

* comment out tests

* property doc fix

* clean up

* Update generate_sdk.py

* make trailmap classes useable for doc generation

* Update generate_sdk.py

* added lineon to trailmap class for linking to func in markdown

* changed lineon to dict

* added full_path to trailmap for linking in docs

* updated portfolio

* feat: initial files

* feat: added meta head

* feat: added funcdef

* added func_def to trailmap attributes for markdown in docs, added missing type hints to covid functions

* feat: added view and merged with jaun

* Update generate_sdk.py

* Update generate_sdk.py

* Update generate_sdk.py

* Update generate_sdk.py

* init

* fix returns

* fix: random stuff

* fix: random

* fixed encoding issue on windows

* fix: generate tabs

* update

* Update generate_sdk_markdown.py

* Create .pydocstyle.ini

* added type hint classes for views

* fixes

* alt, ba

* alt-economy

* Update finviz_compare_model.py

* fixs

* Update substack_model.py

* Update generate_sdk.py

* last of my section

* porfolio

* po

* Update optimizer_model.py

* fixing more things

* few more

* keys done

* update

* fixes

* Update generate_sdk_markdown.py

* Update generate_sdk_markdown.py

* mypy forecast fix

* Update generate_sdk_markdown.py

* Update generate_sdk_markdown.py

* Update generate_sdk_markdown.py

* fixes

* forecast fixes

* one more fix

* Update coinbase_model.py

* Update generate_sdk_markdown.py

Co-authored-by: Colin Delahunty <72827203+colin99d@users.noreply.github.com>
Co-authored-by: James Maslek <jmaslek11@gmail.com>
Co-authored-by: jose-donato <zmcdonato@gmail.com>
Co-authored-by: andrewkenreich <andrew.kenreich@gmail.com>
2022-11-15 16:37:49 -05:00

357 lines
8.7 KiB
Python

"""The Graph model"""
__docformat__ = "numpy"
import datetime
import logging
import pandas as pd
import requests
from openbb_terminal.cryptocurrency.dataframe_helpers import (
lambda_very_long_number_formatter,
)
from openbb_terminal.decorators import log_start_end
from openbb_terminal.rich_config import console
# pylint: disable=unsupported-assignment-operation
logger = logging.getLogger(__name__)
# pylint: disable=unsupported-assignment-operation
UNI_URL = "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2"
SWAPS_FILTERS = ["Datetime", "USD", "From", "To"]
POOLS_FILTERS = [
"volumeUSD",
"token0.name",
"token0.symbol",
"token1.name",
"token1.symbol",
"volumeUSD",
"txCount",
]
TOKENS_FILTERS = [
"index",
"symbol",
"name",
"tradeVolumeUSD",
"totalLiquidity",
"txCount",
]
PAIRS_FILTERS = [
"created",
"pair",
"token0",
"token1",
"volumeUSD",
"txCount",
"totalSupply",
]
# TODO: convert USD values to int. otherwise sort by these columns won't work
@log_start_end(log=logger)
def query_graph(url: str, query: str) -> dict:
"""Helper methods for querying graphql api. [Source: https://thegraph.com/en/]
Parameters
----------
url: str
Endpoint url
query: str
Graphql query
Returns
-------
dict:
Dictionary with response data
"""
response = requests.post(url, json={"query": query})
if response.status_code == 200:
return response.json()["data"]
return {}
@log_start_end(log=logger)
def get_uni_tokens(
skip: int = 0, limit: int = 100, sortby: str = "index", ascend: bool = False
) -> pd.DataFrame:
"""Get list of tokens trade-able on Uniswap DEX. [Source: https://thegraph.com/en/]
Parameters
----------
skip: int
Skip n number of records.
limit: int
Show n number of records.
sortby: str
The column to sort by
ascend: bool
Whether to sort in ascending order
Returns
-------
pd.DataFrame
Uniswap tokens with trading volume, transaction count, liquidity.
"""
limit = min(limit, 1000)
query = f"""
{{
tokens(first: {limit}, skip:{skip}) {{
symbol
name
tradeVolumeUSD
totalLiquidity
txCount
}}
}}
"""
data = query_graph(UNI_URL, query)
if not data:
return pd.DataFrame()
df = pd.DataFrame(data["tokens"]).reset_index()
return df.sort_values(by=sortby, ascending=ascend)
@log_start_end(log=logger)
def get_uniswap_stats() -> pd.DataFrame:
"""Get base statistics about Uniswap DEX. [Source: https://thegraph.com/en/]
uniswapFactory id: 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f - ethereum address on which Uniswap Factory
smart contract was deployed. The factory contract is deployed once from the off-chain source code, and it contains
functions that make it possible to create exchange contracts for any ERC20 token that does not already have one.
It also functions as a registry of ERC20 tokens that have been added to the system, and the exchange with which they
are associated. More: https://docs.uniswap.org/protocol/V1/guides/connect-to-uniswap
We use 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f address to fetch all smart contracts that were
created with usage of this factory.
Returns
-------
pd.DataFrame
Uniswap DEX statistics like liquidity, volume, number of pairs, number of transactions.
"""
query = """
{
uniswapFactory(id: "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"){
totalVolumeUSD
totalLiquidityUSD
pairCount
txCount
totalLiquidityUSD
totalLiquidityETH
}
}
"""
data = query_graph(UNI_URL, query)
if not data:
return pd.DataFrame()
df = pd.Series(data["uniswapFactory"]).reset_index()
df.columns = ["Metric", "Value"]
df["Value"] = df["Value"].apply(lambda x: lambda_very_long_number_formatter(x))
return df
@log_start_end(log=logger)
def get_uniswap_pool_recently_added(
last_days: int = 14,
min_volume: int = 100,
min_liquidity: int = 0,
min_tx: int = 100,
) -> pd.DataFrame:
"""Get lastly added trade-able pairs on Uniswap with parameters like:
* number of days the pair has been active,
* minimum trading volume,
* minimum liquidity,
* number of transactions.
[Source: https://thegraph.com/en/]
Parameters
----------
last_days: int
How many days back to look for added pairs.
min_volume: int
Minimum volume
min_liquidity: int
Minimum liquidity
min_tx: int
Minimum number of transactions done in given pool.
Returns
-------
pd.DataFrame
Lastly added pairs on Uniswap DEX.
"""
days = int(
(datetime.datetime.now() - datetime.timedelta(days=last_days)).timestamp()
)
query = f"""
{{
pairs(first: 1000,
where: {{createdAtTimestamp_gt: "{days}", volumeUSD_gt: "{min_volume}", reserveUSD_gt: "{min_liquidity}",
txCount_gt: "{min_tx}" }},
orderBy: createdAtTimestamp, orderDirection: desc) {{
token0 {{
symbol
name
}}
token1 {{
symbol
name
}}
reserveUSD
volumeUSD
createdAtTimestamp
totalSupply
txCount
}}
}}
"""
data = query_graph(UNI_URL, query)
if not data:
return pd.DataFrame()
df = pd.json_normalize(data["pairs"])
df["createdAtTimestamp"] = df["createdAtTimestamp"].apply(
lambda x: datetime.datetime.fromtimestamp(int(x))
)
df["pair"] = df["token0.symbol"] + "/" + df["token1.symbol"]
df.rename(
columns={
"createdAtTimestamp": "created",
"token0.name": "token0",
"token1.name": "token1",
},
inplace=True,
)
return df[
[
"created",
"pair",
"token0",
"token1",
"volumeUSD",
"txCount",
"totalSupply",
]
]
@log_start_end(log=logger)
def get_uni_pools_by_volume() -> pd.DataFrame:
"""Get uniswap pools by volume. [Source: https://thegraph.com/en/]
Returns
-------
pd.DataFrame
Trade-able pairs listed on Uniswap by top volume.
"""
query = """
{
pairs(first: 1000, where: {reserveUSD_gt: "1000", volumeUSD_gt: "10000"},
orderBy: volumeUSD, orderDirection: desc) {
token0 {
symbol
name
}
token1 {
symbol
name
}
volumeUSD
txCount
}
}
"""
data = query_graph(UNI_URL, query)
if not data:
return pd.DataFrame()
df = pd.json_normalize(data["pairs"])
return df[
[
"token0.name",
"token0.symbol",
"token1.name",
"token1.symbol",
"volumeUSD",
"txCount",
]
]
@log_start_end(log=logger)
def get_last_uni_swaps(
limit: int = 100, sortby: str = "timestamp", ascend: bool = False
) -> pd.DataFrame:
"""Get the last 100 swaps done on Uniswap [Source: https://thegraph.com/en/]
Parameters
----------
limit: int
Number of swaps to return. Maximum possible number: 1000.
sortby: str
Key by which to sort data. The table can be sorted by every of its columns
(see https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2).
ascend: bool
Flag to sort data descending
Returns
-------
pd.DataFrame
Last 100 swaps on Uniswap
"""
limit = min(limit, 1000)
query = f"""
{{
swaps(first: {limit}, orderBy: timestamp, orderDirection: desc) {{
timestamp
pair {{
token0 {{
symbol
}}
token1 {{
symbol
}}
}}
amountUSD
}}
}}
"""
data = query_graph(UNI_URL, query)
if not data:
return pd.DataFrame()
df = pd.json_normalize(data["swaps"])
df["timestamp"] = df["timestamp"].apply(
lambda x: datetime.datetime.fromtimestamp(int(x))
)
df["amountUSD"] = df["amountUSD"].apply(lambda x: round(float(x), 2))
to_rename = {
"timestamp": "Datetime",
"amountUSD": "USD",
"pair.token0.symbol": "From",
"pair.token1.symbol": "To",
}
df = df.rename(columns=to_rename)
if sortby in df.columns:
df = df.sort_values(by=sortby, ascending=ascend)
else:
console.print(f"[red]Dataframe does not have column {sortby}[/red]\n")
return df