Added some experimental JSON output for feedback.

This commit is contained in:
Geoff Taylor 2021-11-19 17:36:25 +00:00
parent 5bcca292a7
commit d2a9946918
11 changed files with 83 additions and 15 deletions

View File

@ -1,5 +1,8 @@
[mypy]
[mypy-jsons.*]
ignore_missing_imports = True
[mypy-pyserum.*]
ignore_missing_imports = True

View File

@ -36,11 +36,7 @@ if oracle is None:
else:
if not args.stream:
price = oracle.fetch_price(context)
confidence = ""
if price.source.supports & mango.SupportedOracleFeature.CONFIDENCE:
confidence = f" +/- {price.confidence:,.8f}"
print(
f"The price of «{oracle.symbol}» on {price.source.provider_name} is: '{price.mid_price:,.8f}'{confidence}")
mango.output(price)
else:
print("Press <ENTER> to quit.")
price_subscription = oracle.to_streaming_observable(context)

View File

@ -28,4 +28,4 @@ perp_market = mango.ensure_market_loaded(context, market)
if not isinstance(perp_market, mango.PerpMarket):
raise Exception(f"Market {market_symbol} is not a perp market.")
print(perp_market.fetch_funding(context))
mango.output(perp_market.fetch_funding(context))

View File

@ -19,7 +19,7 @@ try:
context = mango.ContextBuilder.from_command_line_parameters(args)
group = mango.Group.load(context)
print(group)
mango.output(group)
except Exception as exception:
logging.critical(f"show-group stopped because of exception: {exception} - {traceback.format_exc()}")
except:

View File

@ -25,6 +25,4 @@ if token is None:
token_bank = group.token_bank_by_instrument(token)
interest_rates = token_bank.fetch_interest_rates(context)
print(f"Interest rates for {token.symbol}:")
print(f" Deposit: {interest_rates.deposit:,.2%}")
print(f" Borrow : {interest_rates.borrow:,.2%}")
mango.output(interest_rates)

View File

@ -24,4 +24,4 @@ actual_market = mango.ensure_market_loaded(context, market)
if not isinstance(actual_market, mango.PerpMarket):
raise Exception(f"Market {market_symbol} is not a perp market.")
print(actual_market.underlying_perp_market.liquidity_mining_info)
mango.output(actual_market.underlying_perp_market.liquidity_mining_info)

View File

@ -20,6 +20,7 @@ from .accountscout import AccountScout as AccountScout
from .accountscout import ScoutReport as ScoutReport
from .addressableaccount import AddressableAccount as AddressableAccount
from .arguments import parse_args as parse_args
from .arguments import output as output
from .balancesheet import BalanceSheet as BalanceSheet
from .cache import Cache as Cache
from .cache import MarketCache as MarketCache

View File

@ -14,14 +14,47 @@
# [Email](mailto:hello@blockworks.foundation)
import argparse
import enum
import json
import jsons
import logging
import os
import sys
import typing
from solana.publickey import PublicKey
from .constants import WARNING_DISCLAIMER_TEXT, version
# # 🥭 OutputFormat enum
#
# How should we format any output?
#
class OutputFormat(enum.Enum):
# We use strings here so that argparse can work with these as parameters.
TEXT = "TEXT"
JSON = "JSON"
def __str__(self) -> str:
return self.value
def __repr__(self) -> str:
return f"{self}"
output_format: OutputFormat = OutputFormat.TEXT
def output(obj: typing.Any) -> None:
if output_format == OutputFormat.JSON:
jsons.set_serializer(lambda pubkey, **kwargs: f"{pubkey}", PublicKey)
print(json.dumps(jsons.dump(obj, strip_attr=("data", "logger", "lot_size_converter", "tokens", "tokens_by_index", "slots", "base_tokens", "base_tokens_by_index", "oracles", "oracles_by_index", "spot_markets", "spot_markets_by_index", "perp_markets", "perp_markets_by_index", "shared_quote_token", "liquidity_incentive_token"),
key_transformer=jsons.KEY_TRANSFORMER_CAMELCASE), sort_keys=True, indent=4))
else:
print(obj)
# # 🥭 parse_args
#
# This function parses CLI arguments and sets up common logging for all commands.
@ -31,9 +64,14 @@ def parse_args(parser: argparse.ArgumentParser, logging_default: int = logging.I
help="level of verbosity to log (possible values: DEBUG, INFO, WARNING, ERROR, CRITICAL)")
parser.add_argument("--log-suppress-timestamp", default=False, action="store_true",
help="Suppress timestamp in log output (useful for systems that supply their own timestamp on log messages)")
parser.add_argument("--output-format", type=OutputFormat, default=OutputFormat.TEXT,
choices=list(OutputFormat), help="output format - can be TEXT (the default) or JSON")
args: argparse.Namespace = parser.parse_args()
global output_format
output_format = args.output_format
log_record_format: str = "%(asctime)s %(level_emoji)s %(name)-12.12s %(message)s"
if args.log_suppress_timestamp:
log_record_format = "%(level_emoji)s %(name)-12.12s %(message)s"

View File

@ -86,7 +86,7 @@ class Price():
confidence = ""
if self.source.supports & SupportedOracleFeature.CONFIDENCE:
confidence = f" +/- {self.confidence:,.8f}"
return f"{self.timestamp} [{self.source.provider_name}] {self.market.symbol}: {self.mid_price:,.8f}{confidence}"
return f"« 𝙿𝚛𝚒𝚌𝚎 [{self.source.provider_name}] {self.market.symbol} at {self.timestamp}: {self.mid_price:,.8f}{confidence} »"
def __repr__(self) -> str:
return f"{self}"

33
poetry.lock generated
View File

@ -199,6 +199,20 @@ category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "jsons"
version = "1.6.0"
description = "For serializing Python objects to JSON (dicts) and back"
category = "main"
optional = false
python-versions = ">=3.5"
[package.dependencies]
typish = ">=1.9.2"
[package.extras]
test = ["attrs", "coverage", "codecov", "pytest", "scons", "dataclasses", "tzdata"]
[[package]]
name = "mccabe"
version = "0.6.1"
@ -502,6 +516,17 @@ category = "main"
optional = false
python-versions = "*"
[[package]]
name = "typish"
version = "1.9.3"
description = "Functionality for types"
category = "main"
optional = false
python-versions = "*"
[package.extras]
test = ["numpy", "nptyping (>=1.3.0)", "pycodestyle", "pylint", "mypy", "pytest", "coverage", "codecov"]
[[package]]
name = "urllib3"
version = "1.26.7"
@ -544,7 +569,7 @@ cffi = ["cffi (>=1.11)"]
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
content-hash = "dd2ffa0dda88b822d7449023c4bd9eadb93bf98a2d96136f301c174bef66c122"
content-hash = "d4f21f06e7f1dcc4923f8943aa5c7e10a3ee56b11490685a92c0bca07fc0eb6c"
[metadata.files]
anyio = [
@ -666,6 +691,9 @@ iniconfig = [
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
]
jsons = [
{file = "jsons-1.6.0-py3-none-any.whl", hash = "sha256:493643e28dcb3432aac72b79b1962eb955dfc7807bb7ea76e435efc99e9c4beb"},
]
mccabe = [
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
@ -819,6 +847,9 @@ typing-extensions = [
{file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"},
{file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"},
]
typish = [
{file = "typish-1.9.3-py3-none-any.whl", hash = "sha256:03cfee5e6eb856dbf90244e18f4e4c41044c8790d5779f4e775f63f982e2f896"},
]
urllib3 = [
{file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"},
{file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"},

View File

@ -14,15 +14,16 @@ packages = [
]
[tool.poetry.dependencies]
python = "^3.9"
jsons = "^1.6.0"
pyserum = "^0.5.0a0"
python = "^3.9"
python-dateutil = "^2.8.2"
requests = "^2.22.0"
Rx = "^3.2.0"
rxpy-backpressure = "^1.0.0"
solana = "^0.18.2"
websocket-client = "^1.2.1"
zstandard = "^0.16.0"
python-dateutil = "^2.8.2"
[tool.poetry.dev-dependencies]
autopep8 = "^1.5.7"