Starts crypto tools menu (#1668)

* started crypto tools menu

* allow zero float

* added obb script

Co-authored-by: Chavithra <chavithra@gmail.com>
Co-authored-by: didierlopes.eth <dro.lopes@campus.fct.unl.pt>
Co-authored-by: minhhoang1023 <40023817+minhhoang1023@users.noreply.github.com>
This commit is contained in:
jose-donato
2022-04-14 08:24:42 +01:00
committed by GitHub
parent 670402396e
commit a12e0946da
24 changed files with 902 additions and 1 deletions

View File

@@ -63,7 +63,18 @@ class CryptoController(CryptoBaseController):
"prt",
"resources",
]
CHOICES_MENUS = ["ta", "dd", "ov", "disc", "onchain", "defi", "nft", "pred", "qa"]
CHOICES_MENUS = [
"ta",
"dd",
"ov",
"disc",
"onchain",
"defi",
"tools",
"nft",
"pred",
"qa",
]
DD_VIEWS_MAPPING = {
"cg": pycoingecko_view,
@@ -106,6 +117,7 @@ class CryptoController(CryptoBaseController):
> ov overview of the cryptocurrencies, e.g.: market cap, DeFi, latest news, top exchanges, stables
> onchain information on different blockchains, e.g.: eth gas fees, whale alerts, DEXes info
> defi decentralized finance information, e.g.: dpi, llama, tvl, lending, borrow, funding
> tools explore different tools e.g.: apytoapr, il
> nft non-fungible tokens, e.g.: today drops{has_ticker_start}
> dd due-diligence for loaded coin, e.g.: coin information, social media, market stats
> ta technical analysis for loaded coin, e.g.: ema, macd, rsi, adx, bbands, obv
@@ -430,6 +442,15 @@ class CryptoController(CryptoBaseController):
else:
console.print("No coin selected. Use 'load' to load a coin.\n")
@log_start_end(log=logger)
def call_tools(self, _):
"""Process tools command"""
from openbb_terminal.cryptocurrency.tools.tools_controller import (
ToolsController,
)
self.queue = self.load_class(ToolsController, self.queue)
@log_start_end(log=logger)
def call_disc(self, _):
"""Process disc command"""

View File

@@ -0,0 +1,13 @@
"""Tools context API."""
import os
from openbb_terminal.helper_classes import ModelsNamespace as _models
# flake8: noqa
# pylint: disable=unused-import
# Menu commands
from .tools_view import display_apy as aprtoapy
from .tools_view import display_il as il
# Models
models = _models(os.path.abspath(os.path.dirname(__file__)))

View File

@@ -0,0 +1,180 @@
"""Tools Controller Module"""
__docformat__ = "numpy"
# pylint: disable=C0302
import argparse
import logging
from typing import List
from prompt_toolkit.completion import NestedCompleter
from openbb_terminal import feature_flags as obbff
from openbb_terminal.decorators import log_start_end
from openbb_terminal.helper_funcs import (
EXPORT_ONLY_RAW_DATA_ALLOWED,
check_non_negative_float,
check_percentage_range,
check_positive,
check_positive_float,
parse_known_args_and_warn,
)
from openbb_terminal.cryptocurrency.tools import tools_view
from openbb_terminal.menu import session
from openbb_terminal.parent_classes import BaseController
from openbb_terminal.rich_config import console
logger = logging.getLogger(__name__)
class ToolsController(BaseController):
"""Tools Controller class"""
CHOICES_COMMANDS = ["aprtoapy", "il"]
PATH = "/crypto/tools/"
def __init__(self, queue: List[str] = None):
"""Constructor"""
super().__init__(queue)
if session and obbff.USE_PROMPT_TOOLKIT:
choices: dict = {c: {} for c in self.controller_choices}
self.completer = NestedCompleter.from_nested_dict(choices)
def print_help(self):
"""Print help"""
help_text = """[cmds]
aprtoapy convert apr to apy
il calculate impermanent loss[/cmds]
"""
console.print(text=help_text, menu="Cryptocurrency - Tools")
@log_start_end(log=logger)
def call_il(self, other_args: List[str]):
"""Process il command"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="il",
description="""Tool to calculate Impermanent Loss in a custom liquidity pool.
Users can provide percentages increases for two tokens (and their weight in the liquidity pool)
and verify the impermanent loss that can occur.""",
)
parser.add_argument(
"-pcA",
"--priceChangeA",
dest="priceChangeA",
type=check_non_negative_float,
help="Token A price change in percentage",
default=0,
)
parser.add_argument(
"-pcB",
"--priceChangeB",
dest="priceChangeB",
type=check_non_negative_float,
help="Token B price change in percentage",
default=100,
)
parser.add_argument(
"-p",
"--proportion",
dest="proportion",
type=check_percentage_range,
help="""Pool proportion. E.g., 50 means that pool contains 50%% of token A and 50%% of token B,
30 means that pool contains 30%% of token A and 70%% of token B""",
default=50,
)
parser.add_argument(
"-v",
"--value",
dest="value",
type=check_positive_float,
help="Initial amount of dollars that user provides to liquidity pool",
default=1000,
)
parser.add_argument(
"-n",
"--narrative",
dest="narrative",
action="store_true",
help="Flag to show narrative instead of dataframe",
default=False,
)
if other_args and not other_args[0][0] == "-":
other_args.insert(0, "-pcA")
ns_parser = parse_known_args_and_warn(
parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
)
if ns_parser:
tools_view.display_il(
price_changeA=ns_parser.priceChangeA,
price_changeB=ns_parser.priceChangeB,
proportion=ns_parser.proportion,
initial_pool_value=ns_parser.value,
narrative=ns_parser.narrative,
export=ns_parser.export,
)
@log_start_end(log=logger)
def call_aprtoapy(self, other_args: List[str]):
"""Process aprtoapy command"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="aprtoapy",
description="""
Tool to calculate APY from APR value.
Compouding periods, i.e., the number of times compounded per year
can be defined with -c argument.
""",
)
parser.add_argument(
"--apr",
dest="apr",
type=check_positive_float,
help="APR value in percentage to convert",
default=100,
)
parser.add_argument(
"-c",
"--compounding",
dest="compounding",
type=check_positive,
help="Number of compounded periods in a year. 12 means compounding monthly",
default=12,
)
parser.add_argument(
"-n",
"--narrative",
dest="narrative",
action="store_true",
help="Flag to show narrative instead of dataframe",
default=False,
)
if other_args and not other_args[0][0] == "-":
other_args.insert(0, "--apr")
ns_parser = parse_known_args_and_warn(
parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
)
if ns_parser:
tools_view.display_apy(
apr=ns_parser.apr,
compounding_times=ns_parser.compounding,
narrative=ns_parser.narrative,
export=ns_parser.export,
)

View File

@@ -0,0 +1,58 @@
def change_variation(change: float) -> float:
"""Helper to convert change variation
Parameters
----------
change: float
percentage change
Returns
-------
float:
converted value
"""
return (100 + change) / 100
def calculate_hold_value(changeA: float, changeB: float, proportion: float) -> float:
"""Calculates hold value of two different coins
Parameters
----------
changeA: float
price change of crypto A in percentage
changeB: float
price change of crypto B in percentage
proportion: float
percentage of first token in pool
Returns
-------
float:
hold value
"""
return (change_variation(changeA) * proportion) / 100 + (
(change_variation(changeB) * (100 - proportion)) / 100
)
def calculate_pool_value(changeA, changeB, proportion):
"""Calculates pool value of two different coins
Parameters
----------
changeA: float
price change of crypto A in percentage
changeB: float
price change of crypto B in percentage
proportion: float
percentage of first token in pool
Returns
-------
float:
pool value
"""
return pow(change_variation(changeA), proportion / 100) * pow(
change_variation(changeB), (100 - proportion) / 100
)

View File

@@ -0,0 +1,118 @@
"""Tools Model"""
__docformat__ = "numpy"
import logging
from typing import Tuple
import pandas as pd
from openbb_terminal.cryptocurrency.tools.tools_helpers import (
calculate_hold_value,
calculate_pool_value,
)
from openbb_terminal.decorators import log_start_end
logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def calculate_apy(apr: float, compounding_times: int) -> Tuple[pd.DataFrame, str]:
"""Converts apr into apy
Parameters
----------
apr: float
value in percentage
compounding_times: int
number of compounded periods in a year
Returns
-------
Tuple:
- pd.DataFrame: dataframe with results
- str: narrative version of results
"""
apy = (pow((1 + (apr / 100) / compounding_times), compounding_times) - 1) * 100
apy_str = f"""
An APR of {apr}% compounded {compounding_times} times per year equals to an APY of {round(apy,3)}%
"""
df = pd.DataFrame(
{
"Metric": [
"APR",
"Compounding Times",
"APY",
],
"Value": [
f"{apr}%",
compounding_times,
f"{round(apy, 3)}%",
],
}
)
return df, apy_str
@log_start_end(log=logger)
def calculate_il(
price_changeA: float,
price_changeB: float,
proportion: float,
initial_pool_value: float,
) -> Tuple[pd.DataFrame, str]:
"""Calculates Impermanent Loss in a custom liquidity pool
Parameters
----------
price_changeA: float
price change of crypto A in percentage
price_changeB: float
price change of crypto B in percentage
proportion: float
percentage of first token in pool
initial_pool_value: float
initial value that pool contains
Returns
-------
Tuple:
- pd.DataFrame: dataframe with results
- str: narrative version of results
"""
pool_value = calculate_pool_value(price_changeA, price_changeB, proportion)
hold_value = calculate_hold_value(price_changeA, price_changeB, proportion)
il = abs(((pool_value / hold_value) - 1) * 100)
hold_value = hold_value * initial_pool_value
pool_value = pool_value * initial_pool_value
il_str = f"""
Ignoring fees/rewards and only accounting for impermanent loss:
A change of {price_changeA}% in token A and {price_changeB}% in token B in
a pool with a proportion of {proportion}/{100-proportion} and with an initial
value of ${initial_pool_value} would result in an impermant loss of {round(il,2)}%
If you just hold the tokens you would have ${round(hold_value,2)} whereas
in the pool you would have ${round(pool_value,2)}
"""
df = pd.DataFrame(
{
"Metric": [
"Price Change Token A",
"Price Change Token B",
"Initial Pool Value",
"Proportion",
"Impermanent Loss",
"Hold Value",
"Pool Value",
],
"Value": [
f"{price_changeA}%",
f"{price_changeB}%",
f"${initial_pool_value}",
f"{proportion}/{100-proportion}",
f"{round(il,2)}%",
f"${round(hold_value,2)}",
f"${round(pool_value,2)}",
],
}
)
return df, il_str

View File

@@ -0,0 +1,104 @@
"""Tools View"""
__docformat__ = "numpy"
import logging
import os
from openbb_terminal.cryptocurrency.tools.tools_model import calculate_apy, calculate_il
from openbb_terminal.helper_funcs import export_data, print_rich_table
from openbb_terminal.rich_config import console
from openbb_terminal.decorators import log_start_end
logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_apy(apr: float, compounding_times: int, narrative: bool, export: str):
"""Displays APY value converted from APR
Parameters
----------
apr: float
value in percentage
compounding_times: int
number of compounded periods in a year
narrative: str
display narrative version instead of dataframe
export : str
Export dataframe data to csv,json,xlsx file
Returns
-------
"""
df, apy_str = calculate_apy(apr, compounding_times)
if narrative:
console.print(apy_str)
else:
print_rich_table(
df,
headers=list(df.columns),
show_index=False,
title="APR/APY Calculator",
)
console.print("")
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"aprtoapy",
apy_str,
)
@log_start_end(log=logger)
def display_il(
price_changeA: int,
price_changeB: int,
proportion: int,
initial_pool_value: int,
narrative: bool,
export: str,
):
"""Displays Impermanent Loss in a custom liquidity pool
Parameters
----------
price_changeA: float
price change of crypto A in percentage
price_changeB: float
price change of crypto B in percentage
proportion: float
percentage of first token in pool
initial_pool_value: float
initial value that pool contains
narrative: str
display narrative version instead of dataframe
export : str
Export dataframe data to csv,json,xlsx file
Returns
-------
"""
df, il_str = calculate_il(
price_changeA=price_changeA,
price_changeB=price_changeB,
proportion=proportion,
initial_pool_value=initial_pool_value,
)
if narrative:
console.print(il_str)
else:
print_rich_table(
df,
headers=list(df.columns),
show_index=False,
title="Impermanent Loss Calculator",
)
console.print("")
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"il",
df,
)

View File

@@ -317,6 +317,31 @@ def check_positive_float(value) -> float:
return new_value
def check_percentage_range(num) -> float:
"""
Checks if float is between 0 and 100. If so, return it.
Parameters
----------
num: float
Input float
Returns
-------
num: float
Input number if conditions are met
Raises
-------
argparse.ArgumentTypeError
Input number not between min and max values
"""
num = float(num)
maxi = 100.0
mini = 0.0
if num <= mini or num >= maxi:
log_and_raise(argparse.ArgumentTypeError("Value must be between 0 and 100"))
return num
def check_proportion_range(num) -> float:
"""
Checks if float is between 0 and 1. If so, return it.

5
scripts/test_crypto_tools.openbb vendored Normal file
View File

@@ -0,0 +1,5 @@
crypto
tools
aprtoapy
il
exit

View File

@@ -292,6 +292,13 @@ def test_call_func_expect_queue(expected_queue, func, queue):
[],
dict(),
),
(
"call_tools",
[],
"CryptoController.load_class",
[],
dict(),
),
],
)
def test_call_func(

View File

@@ -0,0 +1,4 @@
,Metric,Value
0,APR,100%
1,Compounding Times,12
2,APY,161.304%
1 Metric Value
2 0 APR 100%
3 1 Compounding Times 12
4 2 APY 161.304%

View File

@@ -0,0 +1,8 @@
,Metric,Value
0,Price Change Token A,100%
1,Price Change Token B,200%
2,Initial Pool Value,$1000
3,Proportion,50/50
4,Impermanent Loss,2.02%
5,Hold Value,$2500.0
6,Pool Value,$2449.49
1 Metric Value
2 0 Price Change Token A 100%
3 1 Price Change Token B 200%
4 2 Initial Pool Value $1000
5 3 Proportion 50/50
6 4 Impermanent Loss 2.02%
7 5 Hold Value $2500.0
8 6 Pool Value $2449.49

View File

@@ -0,0 +1,224 @@
# IMPORTATION STANDARD
import os
# IMPORTATION THIRDPARTY
import pytest
# IMPORTATION INTERNAL
from openbb_terminal.cryptocurrency.tools import tools_controller
# pylint: disable=E1101
# pylint: disable=W0603
# pylint: disable=E1111
@pytest.mark.vcr(record_mode="none")
@pytest.mark.parametrize(
"queue, expected",
[
(["load", "help"], []),
(["quit", "help"], ["help"]),
],
)
def test_menu_with_queue(expected, mocker, queue):
path_controller = "openbb_terminal.cryptocurrency.tools.tools_controller"
# MOCK SWITCH
mocker.patch(
target=f"{path_controller}.ToolsController.switch",
return_value=["quit"],
)
result_menu = tools_controller.ToolsController(queue=queue).menu()
assert result_menu == expected
@pytest.mark.vcr(record_mode="none")
def test_menu_without_queue_completion(mocker):
path_controller = "openbb_terminal.cryptocurrency.tools.tools_controller"
# ENABLE AUTO-COMPLETION : HELPER_FUNCS.MENU
mocker.patch(
target="openbb_terminal.feature_flags.USE_PROMPT_TOOLKIT",
new=True,
)
mocker.patch(
target="openbb_terminal.parent_classes.session",
)
mocker.patch(
target="openbb_terminal.parent_classes.session.prompt",
return_value="quit",
)
# DISABLE AUTO-COMPLETION : CONTROLLER.COMPLETER
mocker.patch.object(
target=tools_controller.obbff,
attribute="USE_PROMPT_TOOLKIT",
new=True,
)
mocker.patch(
target=f"{path_controller}.session",
)
mocker.patch(
target=f"{path_controller}.session.prompt",
return_value="quit",
)
result_menu = tools_controller.ToolsController(queue=None).menu()
assert result_menu == []
@pytest.mark.vcr(record_mode="none")
@pytest.mark.parametrize(
"mock_input",
["help", "homee help", "home help", "mock"],
)
def test_menu_without_queue_sys_exit(mock_input, mocker):
path_controller = "openbb_terminal.cryptocurrency.tools.tools_controller"
# DISABLE AUTO-COMPLETION
mocker.patch.object(
target=tools_controller.obbff,
attribute="USE_PROMPT_TOOLKIT",
new=False,
)
mocker.patch(
target=f"{path_controller}.session",
return_value=None,
)
# MOCK USER INPUT
mocker.patch("builtins.input", return_value=mock_input)
# MOCK SWITCH
class SystemExitSideEffect:
def __init__(self):
self.first_call = True
def __call__(self, *args, **kwargs):
if self.first_call:
self.first_call = False
raise SystemExit()
return ["quit"]
mock_switch = mocker.Mock(side_effect=SystemExitSideEffect())
mocker.patch(
target=f"{path_controller}.ToolsController.switch",
new=mock_switch,
)
result_menu = tools_controller.ToolsController(queue=None).menu()
assert result_menu == []
@pytest.mark.vcr(record_mode="none")
@pytest.mark.record_stdout
def test_print_help():
controller = tools_controller.ToolsController(queue=None)
controller.print_help()
@pytest.mark.vcr(record_mode="none")
@pytest.mark.parametrize(
"an_input, expected_queue",
[
("", []),
("/help", ["home", "help"]),
("help/help", ["help", "help"]),
("q", ["quit"]),
("h", []),
(
"r",
["quit", "quit", "reset", "crypto", "tools"],
),
],
)
def test_switch(an_input, expected_queue):
controller = tools_controller.ToolsController(queue=None)
queue = controller.switch(an_input=an_input)
assert queue == expected_queue
@pytest.mark.vcr(record_mode="none")
def test_call_cls(mocker):
mocker.patch("os.system")
controller = tools_controller.ToolsController(queue=None)
controller.call_cls([])
assert controller.queue == []
os.system.assert_called_once_with("cls||clear")
@pytest.mark.vcr(record_mode="none")
@pytest.mark.parametrize(
"func, queue, expected_queue",
[
(
"call_exit",
[],
["quit", "quit", "quit"],
),
("call_exit", ["help"], ["quit", "quit", "quit", "help"]),
("call_home", [], ["quit", "quit"]),
("call_help", [], []),
("call_quit", [], ["quit"]),
("call_quit", ["help"], ["quit", "help"]),
(
"call_reset",
[],
["quit", "quit", "reset", "crypto", "tools"],
),
(
"call_reset",
["help"],
["quit", "quit", "reset", "crypto", "tools", "help"],
),
],
)
def test_call_func_expect_queue(expected_queue, func, queue):
controller = tools_controller.ToolsController(queue=queue)
result = getattr(controller, func)([])
assert result is None
assert controller.queue == expected_queue
@pytest.mark.vcr(record_mode="none")
@pytest.mark.parametrize(
"tested_func, other_args, mocked_func, called_args, called_kwargs",
[
(
"call_aprtoapy",
[],
"tools_view.display_apy",
[],
dict(),
),
],
)
def test_call_func(
tested_func, mocked_func, other_args, called_args, called_kwargs, mocker
):
path_controller = "openbb_terminal.cryptocurrency.tools.tools_controller"
if mocked_func:
mock = mocker.Mock()
mocker.patch(
target=f"{path_controller}.{mocked_func}",
new=mock,
)
controller = tools_controller.ToolsController(queue=None)
getattr(controller, tested_func)(other_args)
if called_args or called_kwargs:
mock.assert_called_once_with(*called_args, **called_kwargs)
else:
mock.assert_called_once()
else:
controller = tools_controller.ToolsController(queue=None)
getattr(controller, tested_func)(other_args)

View File

@@ -0,0 +1,33 @@
# IMPORTATION STANDARD
# IMPORTATION THIRDPARTY
import pytest
# IMPORTATION INTERNAL
from openbb_terminal.cryptocurrency.tools import tools_model
@pytest.mark.vcr
@pytest.mark.parametrize(
"apr,compound_times",
[(100, 12)],
)
def test_calculate_apy(apr, compound_times, recorder):
df, _ = tools_model.calculate_apy(apr=apr, compounding_times=compound_times)
recorder.capture(df)
@pytest.mark.vcr
@pytest.mark.parametrize(
"price_changeA,price_changeB,proportion,initial_pool_value", [(100, 200, 50, 1000)]
)
def test_calculate_il(
price_changeA, price_changeB, proportion, initial_pool_value, recorder
):
df, _ = tools_model.calculate_il(
price_changeA=price_changeA,
price_changeB=price_changeB,
proportion=proportion,
initial_pool_value=initial_pool_value,
)
recorder.capture(df)

View File

@@ -0,0 +1,37 @@
# IMPORTATION STANDARD
# IMPORTATION THIRDPARTY
import pytest
# IMPORTATION INTERNAL
from openbb_terminal.cryptocurrency.tools import tools_view
@pytest.mark.vcr
@pytest.mark.record_stdout
def test_display_il(mocker):
# MOCK EXPORT_DATA
mocker.patch(target="openbb_terminal.cryptocurrency.tools.tools_view.export_data")
tools_view.display_il(
price_changeA=100,
price_changeB=200,
proportion=50,
initial_pool_value=1000,
narrative=False,
export="",
)
@pytest.mark.vcr
@pytest.mark.record_stdout
def test_display_apy(mocker):
# MOCK EXPORT_DATA
mocker.patch(target="openbb_terminal.cryptocurrency.tools.tools_view.export_data")
tools_view.display_apy(
apr=100,
compounding_times=12,
narrative=False,
export="",
)

View File

@@ -0,0 +1,4 @@
aprtoapy convert apr to apy
il calculate impermanent loss

View File

@@ -0,0 +1,5 @@
Metric Value
0 APR 100%
1 Compounding Times 12
2 APY 161.304%

View File

@@ -0,0 +1,9 @@
Metric Value
0 Price Change Token A 100%
1 Price Change Token B 200%
2 Initial Pool Value $1000
3 Proportion 50/50
4 Impermanent Loss 2.02%
5 Hold Value $2500.0
6 Pool Value $2449.49

View File

@@ -13,6 +13,7 @@ Source:
> ov overview of the cryptocurrencies, e.g.: market cap, DeFi, latest news, top exchanges, stables
> onchain information on different blockchains, e.g.: eth gas fees, whale alerts, DEXes info
> defi decentralized finance information, e.g.: dpi, llama, tvl, lending, borrow, funding
> tools explore different tools e.g.: apytoapr, il
> nft non-fungible tokens, e.g.: today drops[unvl]
> dd due-diligence for loaded coin, e.g.: coin information, social media, market stats
> ta technical analysis for loaded coin, e.g.: ema, macd, rsi, adx, bbands, obv

View File

@@ -0,0 +1,5 @@
---
geekdocCollapseSection: true
---
{{< toc-tree >}}

View File

@@ -0,0 +1,13 @@
`usage: aprtoapy [--apr APR] [-c COMPOUNDING] [-n] [-h] [--export EXPORT]`
Tool to calculate APY from APR value. Compouding periods, i.e., the number of times compounded per year can be defined with -c argument.
```
optional arguments:
--apr APR APR value in percentage to convert (default: 100)
-c COMPOUNDING, --compounding COMPOUNDING
Number of compounded periods in a year. 12 means compounding monthly (default: 12)
-n, --narrative Flag to show narra`ive instead of dataframe (default: False)
-h, --help show this help message (default: False)
--export EXPORT Export raw data into csv, json, xlsx (default: )
```

View File

@@ -0,0 +1,20 @@
`usage: il [-pcA PRICECHANGEA] [-pcB PRICECHANGEB] [-p PROPORTION] [-v VALUE] [-n] [-h] [--export EXPORT`
Tool to calculate Impermanent Loss in a custom liquidity pool. Users can provide percentages increases for two tokens (and their weight in
the liquidity pool) and verify the impermanent loss that can occur.
```
optional arguments:
-pcA PRICECHANGEA, --priceChangeA PRICECHANGEA
Token A price change in percentage (default: 0)
-pcB PRICECHANGEB, --priceChangeB PRICECHANGEB
Token B price change in percentage (default: 100)
-p PROPORTION, --proportion PROPORTION
Pool proportion. E.g., 50 means that pool contains 50% of token A and 50% of token B, 30 means that pool contains
30% of token A and 70% of token B (default: 50)
-v VALUE, --value VALUE
Initial amount of dollars that user provides to liquidity pool (default: 1000)
-n, --narrative Flag to show narrative instead of dataframe (default: False)
-h, --help show this help message (default: False)
--export EXPORT Export raw data into csv, json, xlsx (default: )
```

View File

@@ -666,6 +666,13 @@ main:
ref: "/terminal/cryptocurrency/discovery/cpsearch"
- name: cmctop
ref: "/terminal/cryptocurrency/discovery/cmctop"
- name: tools
ref: "/terminal/cryptocurrency/tools"
sub:
- name: aprtoapy
ref: "/terminal/cryptocurrency/tools/aprtoapy"
- name: il
ref: "/terminal/cryptocurrency/tools/il"
- name: overview
ref: "/terminal/cryptocurrency/overview"
sub: