commit
9f47515f59
|
@ -23,7 +23,6 @@ from operator import attrgetter
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
import click
|
import click
|
||||||
import pandas as pd
|
|
||||||
import trio
|
import trio
|
||||||
import tractor
|
import tractor
|
||||||
|
|
||||||
|
@ -47,8 +46,10 @@ _watchlists_data_path = os.path.join(_config_dir, 'watchlists.json')
|
||||||
@click.argument('kwargs', nargs=-1)
|
@click.argument('kwargs', nargs=-1)
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
def api(config, meth, kwargs, keys):
|
def api(config, meth, kwargs, keys):
|
||||||
"""Make a broker-client API method call
|
'''
|
||||||
"""
|
Make a broker-client API method call
|
||||||
|
|
||||||
|
'''
|
||||||
# global opts
|
# global opts
|
||||||
broker = config['brokers'][0]
|
broker = config['brokers'][0]
|
||||||
|
|
||||||
|
@ -79,13 +80,13 @@ def api(config, meth, kwargs, keys):
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option('--df-output', '-df', flag_value=True,
|
|
||||||
help='Output in `pandas.DataFrame` format')
|
|
||||||
@click.argument('tickers', nargs=-1, required=True)
|
@click.argument('tickers', nargs=-1, required=True)
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
def quote(config, tickers, df_output):
|
def quote(config, tickers):
|
||||||
"""Print symbol quotes to the console
|
'''
|
||||||
"""
|
Print symbol quotes to the console
|
||||||
|
|
||||||
|
'''
|
||||||
# global opts
|
# global opts
|
||||||
brokermod = config['brokermods'][0]
|
brokermod = config['brokermods'][0]
|
||||||
|
|
||||||
|
@ -100,28 +101,19 @@ def quote(config, tickers, df_output):
|
||||||
if ticker not in syms:
|
if ticker not in syms:
|
||||||
brokermod.log.warn(f"Could not find symbol {ticker}?")
|
brokermod.log.warn(f"Could not find symbol {ticker}?")
|
||||||
|
|
||||||
if df_output:
|
click.echo(colorize_json(quotes))
|
||||||
cols = next(filter(bool, quotes)).copy()
|
|
||||||
cols.pop('symbol')
|
|
||||||
df = pd.DataFrame(
|
|
||||||
(quote or {} for quote in quotes),
|
|
||||||
columns=cols,
|
|
||||||
)
|
|
||||||
click.echo(df)
|
|
||||||
else:
|
|
||||||
click.echo(colorize_json(quotes))
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option('--df-output', '-df', flag_value=True,
|
|
||||||
help='Output in `pandas.DataFrame` format')
|
|
||||||
@click.option('--count', '-c', default=1000,
|
@click.option('--count', '-c', default=1000,
|
||||||
help='Number of bars to retrieve')
|
help='Number of bars to retrieve')
|
||||||
@click.argument('symbol', required=True)
|
@click.argument('symbol', required=True)
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
def bars(config, symbol, count, df_output):
|
def bars(config, symbol, count):
|
||||||
"""Retreive 1m bars for symbol and print on the console
|
'''
|
||||||
"""
|
Retreive 1m bars for symbol and print on the console
|
||||||
|
|
||||||
|
'''
|
||||||
# global opts
|
# global opts
|
||||||
brokermod = config['brokermods'][0]
|
brokermod = config['brokermods'][0]
|
||||||
|
|
||||||
|
@ -133,7 +125,7 @@ def bars(config, symbol, count, df_output):
|
||||||
brokermod,
|
brokermod,
|
||||||
symbol,
|
symbol,
|
||||||
count=count,
|
count=count,
|
||||||
as_np=df_output
|
as_np=False,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -141,10 +133,7 @@ def bars(config, symbol, count, df_output):
|
||||||
log.error(f"No quotes could be found for {symbol}?")
|
log.error(f"No quotes could be found for {symbol}?")
|
||||||
return
|
return
|
||||||
|
|
||||||
if df_output:
|
click.echo(colorize_json(bars))
|
||||||
click.echo(pd.DataFrame(bars))
|
|
||||||
else:
|
|
||||||
click.echo(colorize_json(bars))
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
|
@ -156,8 +145,10 @@ def bars(config, symbol, count, df_output):
|
||||||
@click.argument('name', nargs=1, required=True)
|
@click.argument('name', nargs=1, required=True)
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
def record(config, rate, name, dhost, filename):
|
def record(config, rate, name, dhost, filename):
|
||||||
"""Record client side quotes to a file on disk
|
'''
|
||||||
"""
|
Record client side quotes to a file on disk
|
||||||
|
|
||||||
|
'''
|
||||||
# global opts
|
# global opts
|
||||||
brokermod = config['brokermods'][0]
|
brokermod = config['brokermods'][0]
|
||||||
loglevel = config['loglevel']
|
loglevel = config['loglevel']
|
||||||
|
@ -195,8 +186,10 @@ def record(config, rate, name, dhost, filename):
|
||||||
@click.argument('symbol', required=True)
|
@click.argument('symbol', required=True)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def contracts(ctx, loglevel, broker, symbol, ids):
|
def contracts(ctx, loglevel, broker, symbol, ids):
|
||||||
"""Get list of all option contracts for symbol
|
'''
|
||||||
"""
|
Get list of all option contracts for symbol
|
||||||
|
|
||||||
|
'''
|
||||||
brokermod = get_brokermod(broker)
|
brokermod = get_brokermod(broker)
|
||||||
get_console_log(loglevel)
|
get_console_log(loglevel)
|
||||||
|
|
||||||
|
@ -213,14 +206,14 @@ def contracts(ctx, loglevel, broker, symbol, ids):
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option('--df-output', '-df', flag_value=True,
|
|
||||||
help='Output in `pandas.DataFrame` format')
|
|
||||||
@click.option('--date', '-d', help='Contracts expiry date')
|
@click.option('--date', '-d', help='Contracts expiry date')
|
||||||
@click.argument('symbol', required=True)
|
@click.argument('symbol', required=True)
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
def optsquote(config, symbol, df_output, date):
|
def optsquote(config, symbol, date):
|
||||||
"""Retreive symbol option quotes on the console
|
'''
|
||||||
"""
|
Retreive symbol option quotes on the console
|
||||||
|
|
||||||
|
'''
|
||||||
# global opts
|
# global opts
|
||||||
brokermod = config['brokermods'][0]
|
brokermod = config['brokermods'][0]
|
||||||
|
|
||||||
|
@ -233,22 +226,17 @@ def optsquote(config, symbol, df_output, date):
|
||||||
log.error(f"No option quotes could be found for {symbol}?")
|
log.error(f"No option quotes could be found for {symbol}?")
|
||||||
return
|
return
|
||||||
|
|
||||||
if df_output:
|
click.echo(colorize_json(quotes))
|
||||||
df = pd.DataFrame(
|
|
||||||
(quote.values() for quote in quotes),
|
|
||||||
columns=quotes[0].keys(),
|
|
||||||
)
|
|
||||||
click.echo(df)
|
|
||||||
else:
|
|
||||||
click.echo(colorize_json(quotes))
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument('tickers', nargs=-1, required=True)
|
@click.argument('tickers', nargs=-1, required=True)
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
def symbol_info(config, tickers):
|
def symbol_info(config, tickers):
|
||||||
"""Print symbol quotes to the console
|
'''
|
||||||
"""
|
Print symbol quotes to the console
|
||||||
|
|
||||||
|
'''
|
||||||
# global opts
|
# global opts
|
||||||
brokermod = config['brokermods'][0]
|
brokermod = config['brokermods'][0]
|
||||||
|
|
||||||
|
@ -270,8 +258,10 @@ def symbol_info(config, tickers):
|
||||||
@click.argument('pattern', required=True)
|
@click.argument('pattern', required=True)
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
def search(config, pattern):
|
def search(config, pattern):
|
||||||
"""Search for symbols from broker backend(s).
|
'''
|
||||||
"""
|
Search for symbols from broker backend(s).
|
||||||
|
|
||||||
|
'''
|
||||||
# global opts
|
# global opts
|
||||||
brokermods = config['brokermods']
|
brokermods = config['brokermods']
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,6 @@ import pendulum
|
||||||
import trio
|
import trio
|
||||||
import tractor
|
import tractor
|
||||||
from async_generator import asynccontextmanager
|
from async_generator import asynccontextmanager
|
||||||
import pandas as pd
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import wrapt
|
import wrapt
|
||||||
import asks
|
import asks
|
||||||
|
@ -669,7 +668,7 @@ def get_OHLCV(
|
||||||
"""
|
"""
|
||||||
del bar['end']
|
del bar['end']
|
||||||
del bar['VWAP']
|
del bar['VWAP']
|
||||||
bar['start'] = pd.Timestamp(bar['start']).value/10**9
|
bar['start'] = pendulum.from_timestamp(bar['start']) / 10**9
|
||||||
return tuple(bar.values())
|
return tuple(bar.values())
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,6 @@ from bidict import bidict
|
||||||
import msgpack
|
import msgpack
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
|
||||||
import tractor
|
import tractor
|
||||||
from trio_websocket import open_websocket_url
|
from trio_websocket import open_websocket_url
|
||||||
from anyio_marketstore import (
|
from anyio_marketstore import (
|
||||||
|
@ -268,7 +267,7 @@ def quote_to_marketstore_structarray(
|
||||||
'''
|
'''
|
||||||
if last_fill:
|
if last_fill:
|
||||||
# new fill bby
|
# new fill bby
|
||||||
now = timestamp(last_fill)
|
now = int(pendulum.parse(last_fill).timestamp)
|
||||||
else:
|
else:
|
||||||
# this should get inserted upstream by the broker-client to
|
# this should get inserted upstream by the broker-client to
|
||||||
# subtract from IPC latency
|
# subtract from IPC latency
|
||||||
|
@ -298,15 +297,6 @@ def quote_to_marketstore_structarray(
|
||||||
return np.array([tuple(array_input)], dtype=_quote_dt)
|
return np.array([tuple(array_input)], dtype=_quote_dt)
|
||||||
|
|
||||||
|
|
||||||
def timestamp(date, **kwargs) -> int:
|
|
||||||
'''
|
|
||||||
Return marketstore compatible 'Epoch' integer in nanoseconds
|
|
||||||
from a date formatted str.
|
|
||||||
|
|
||||||
'''
|
|
||||||
return int(pd.Timestamp(date, **kwargs).value)
|
|
||||||
|
|
||||||
|
|
||||||
@acm
|
@acm
|
||||||
async def get_client(
|
async def get_client(
|
||||||
host: str = 'localhost',
|
host: str = 'localhost',
|
||||||
|
|
|
@ -19,10 +19,10 @@ Chart axes graphics and behavior.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from typing import List, Tuple, Optional, Callable
|
from typing import Optional, Callable
|
||||||
from math import floor
|
from math import floor
|
||||||
|
|
||||||
import pandas as pd
|
import numpy as np
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
from PyQt5.QtCore import QPointF
|
from PyQt5.QtCore import QPointF
|
||||||
|
@ -103,7 +103,7 @@ class Axis(pg.AxisItem):
|
||||||
def size_to_values(self) -> None:
|
def size_to_values(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def txt_offsets(self) -> Tuple[int, int]:
|
def txt_offsets(self) -> tuple[int, int]:
|
||||||
return tuple(self.style['tickTextOffset'])
|
return tuple(self.style['tickTextOffset'])
|
||||||
|
|
||||||
|
|
||||||
|
@ -218,9 +218,9 @@ class DynamicDateAxis(Axis):
|
||||||
|
|
||||||
def _indexes_to_timestrs(
|
def _indexes_to_timestrs(
|
||||||
self,
|
self,
|
||||||
indexes: List[int],
|
indexes: list[int],
|
||||||
|
|
||||||
) -> List[str]:
|
) -> list[str]:
|
||||||
|
|
||||||
chart = self.linkedsplits.chart
|
chart = self.linkedsplits.chart
|
||||||
bars = chart._arrays[chart.name]
|
bars = chart._arrays[chart.name]
|
||||||
|
@ -241,10 +241,17 @@ class DynamicDateAxis(Axis):
|
||||||
)]
|
)]
|
||||||
|
|
||||||
# TODO: **don't** have this hard coded shift to EST
|
# TODO: **don't** have this hard coded shift to EST
|
||||||
dts = pd.to_datetime(epochs, unit='s') # - 4*pd.offsets.Hour()
|
# delay = times[-1] - times[-2]
|
||||||
|
dts = np.array(epochs, dtype='datetime64[s]')
|
||||||
|
|
||||||
delay = times[-1] - times[-2]
|
# see units listing:
|
||||||
return dts.strftime(self.tick_tpl[delay])
|
# https://numpy.org/devdocs/reference/arrays.datetime.html#datetime-units
|
||||||
|
return list(np.datetime_as_string(dts))
|
||||||
|
|
||||||
|
# TODO: per timeframe formatting?
|
||||||
|
# - we probably need this based on zoom now right?
|
||||||
|
# prec = self.np_dt_precision[delay]
|
||||||
|
# return dts.strftime(self.tick_tpl[delay])
|
||||||
|
|
||||||
def tickStrings(
|
def tickStrings(
|
||||||
self,
|
self,
|
||||||
|
@ -430,7 +437,7 @@ class XAxisLabel(AxisLabel):
|
||||||
| QtCore.Qt.AlignCenter
|
| QtCore.Qt.AlignCenter
|
||||||
)
|
)
|
||||||
|
|
||||||
def size_hint(self) -> Tuple[float, float]:
|
def size_hint(self) -> tuple[float, float]:
|
||||||
# size to parent axis height
|
# size to parent axis height
|
||||||
return self._parent.height(), None
|
return self._parent.height(), None
|
||||||
|
|
||||||
|
@ -444,11 +451,11 @@ class XAxisLabel(AxisLabel):
|
||||||
|
|
||||||
timestrs = self._parent._indexes_to_timestrs([int(value)])
|
timestrs = self._parent._indexes_to_timestrs([int(value)])
|
||||||
|
|
||||||
if not timestrs.any():
|
if not len(timestrs):
|
||||||
return
|
return
|
||||||
|
|
||||||
pad = 1*' '
|
pad = 1*' '
|
||||||
self.label_str = pad + timestrs[0] + pad
|
self.label_str = pad + str(timestrs[0]) + pad
|
||||||
|
|
||||||
_, y_offset = self._parent.txt_offsets()
|
_, y_offset = self._parent.txt_offsets()
|
||||||
|
|
||||||
|
@ -509,7 +516,7 @@ class YAxisLabel(AxisLabel):
|
||||||
if getattr(self._parent, 'txt_offsets', False):
|
if getattr(self._parent, 'txt_offsets', False):
|
||||||
self.x_offset, y_offset = self._parent.txt_offsets()
|
self.x_offset, y_offset = self._parent.txt_offsets()
|
||||||
|
|
||||||
def size_hint(self) -> Tuple[float, float]:
|
def size_hint(self) -> tuple[float, float]:
|
||||||
# size to parent axis width(-ish)
|
# size to parent axis width(-ish)
|
||||||
wsh = self._dpifont.boundingRect(' ').height() / 2
|
wsh = self._dpifont.boundingRect(' ').height() / 2
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Reference in New Issue