Commit Graph

352 Commits (ccaedfae3fe82a101642defeb873fa49a44b35f0)

Author SHA1 Message Date
Tyler Goodlet 5f200b8db1 Always delay bars 15m; rename to volume 2020-05-26 14:49:50 -04:00
Tyler Goodlet a7f7de32b4 Docstring tweaks 2020-05-26 14:49:50 -04:00
Tyler Goodlet ffd8bdac5f Fix imports 2020-05-26 14:49:50 -04:00
Tyler Goodlet 9b91ecd408 Pass confdir and watchlist path to cli 2020-05-26 14:49:50 -04:00
Tyler Goodlet 057086efdb Pass through test file to monitor 2020-05-26 14:49:50 -04:00
Tyler Goodlet f798d13038 Reord watchlist cmds into new package 2020-05-26 14:49:50 -04:00
Tyler Goodlet ff843372a1 Add `piker bars` command
For easy testing of questrade historical data from cli.
Re-org the common cli components into a new package to avoid having all
commands defined in a top-level module.
2020-05-26 14:49:50 -04:00
Tyler Goodlet c11946988e Implement candles retrieval from Questrade
There's some expected limitations with the number of sticks allowed in
a single query (they say 2k but I've been able to pull 20k). Also note
without a paid data sub there's a 15m delay on 1m sticks (we'll hack
around that shortly, don't worry).
2020-05-26 14:49:50 -04:00
Tyler Goodlet 595f79c632 Add symbol not found 2020-05-26 14:49:50 -04:00
Tyler Goodlet 732638ae2d Delegate logging to `tractor`
Gives us PIDs and task ids in logs which is much more sane for
debugging and cuts down on superfluous code.
2020-02-29 12:29:20 -05:00
Tyler Goodlet 837e30ff68 use >1 asks session connections
Gets us better throughput when polling multiple endpoints (eg. option
and stock quotes simultaneously) since slower round trip request won't
block faster ones when using multiple connections.
2020-02-18 16:13:20 -05:00
Tyler Goodlet a2e5d07b2c Port to mainline kivy and Python 3.8
This required some copy-paste of code from @matham's branch:
https://github.com/kivy/kivy/pull/5241

namely, the stuff in the `utils_async.py` module. I've added all that as
a standalone file for now.

Update the pipfile to use `kivy`'s master branch (since there seems to
be some lingering cython issues in the current release wheels).
2019-11-21 10:21:43 -05:00
Tyler Goodlet 49d612de49 Port to new @tractor.stream API 2019-04-26 00:27:01 -04:00
Tyler Goodlet 1cc33abca0 Don't bail when a sub-optschain crashes 2019-03-24 12:09:17 -04:00
Tyler Goodlet b2252e5762 Fix bad import 2019-03-21 22:18:09 -04:00
Tyler Goodlet 8bf82a2f76 Allow spawning an optschain UI from monitor using the `o` keybinding 2019-03-21 22:15:08 -04:00
Tyler Goodlet d59283d36d Update optschain cli entrypoint to pass primitive arg types 2019-03-21 22:14:22 -04:00
Tyler Goodlet 884fcaa88e A slew of tiny pager improvements
- stop displaying search bar widget on <ctrl-c>
- if there's existing search bar content highlight it automatically
  to allow user to start typing new content right away
- when activated allow search bar to insert its own set of keybinding
  controls; restore prior bindings on exit
2019-03-21 22:01:50 -04:00
Tyler Goodlet 3bbb1db2b4 Make option chain spawnable as a subactor
Look up the broker module and set up the loglevel locally.
Ask the arbiter for a portal to the data daemon since we can't
pass one to a subactor by reference.
2019-03-21 21:50:55 -04:00
Tyler Goodlet fc1e63b2c1 Spawn keyboard functions in new tasks 2019-03-18 22:39:21 -04:00
Tyler Goodlet c8da096126 Track table's last clicked row 2019-03-18 22:38:32 -04:00
Tyler Goodlet 3a439fc99d Fix ask use logic for testing/CI 2019-03-17 23:03:45 -04:00
Tyler Goodlet 6a50049af7 Use toml instead of ini for broker config 2019-03-15 19:37:04 -04:00
Tyler Goodlet 5e9c38039c Move brokerd spawner to `brokers.core` 2019-02-25 22:29:48 -05:00
Tyler Goodlet d3fae00e74 Add a `configdir` cli option 2019-02-25 20:22:29 -05:00
Tyler Goodlet 747d703d92 Add hack-fix to avoid leaking cmdline flags to kivy 2019-02-25 20:14:36 -05:00
Tyler Goodlet 77548d2ee6 Add token-from-user toggles to token auth methods 2019-02-25 20:11:45 -05:00
Tyler Goodlet 130553b8df Accept a path arg to `write()` 2019-02-25 19:29:54 -05:00
Tyler Goodlet 295ccbbe64 Name the data what it is 2019-02-24 10:55:52 -05:00
Tyler Goodlet c1a398d826 Use click context to factor cmd options 2019-02-23 16:13:04 -05:00
Tyler Goodlet 7ee731faac Use trio memory channels throughout UIs 2019-02-21 23:09:19 -05:00
Tyler Goodlet cbb973ae9d Drop internal nursery from option chain 2019-02-21 23:07:44 -05:00
Tyler Goodlet 462c419970 Add basic practice account support 2019-02-21 17:24:50 -05:00
Tyler Goodlet 435b2a56e8 Remove stream opening lock on `DataFeed`
Fixes to `tractor` that resolve issues with async generators being
non-task safe make the need for the mutex lock in
`DataFeed.open_stream()` unnecessary. Also, don't bother pushing empty
quotes from the publisher; avoids hitting the network when possible.
2019-02-20 21:39:57 -05:00
Tyler Goodlet 3a6efd451d Don't bother ensuring all symbols in data 2019-02-10 19:09:54 -05:00
Tyler Goodlet 3ab9e28ddb Use brokerd's client to get all contracts 2019-02-09 21:58:27 -05:00
Tyler Goodlet 395f0c8e4a Synchronize Questrade token refreshing per client
Questrade's API is half baked and can't handle concurrency.
It allows multiple concurrent requests to most endpoints *except*
for the auth endpoint used to refresh tokens:

    https://www.questrade.com/api/documentation/security

I've gone through extensive dialogue with their API team and despite
making what I think are very good arguments for doing the request
serialization on the server side, they decided that I should instead
do the "locking" on the client side. Frankly it doesn't seem like they
have that competent an engineering department as it took me a long time
to explain the issue even though it's rather trivial and probably not
that hard to fix; maybe it's better this way.

This adds a few things to ensure more reliable token refreshes on
expiry:

- add a `@refresh_token_on_err` decorator which can be used on `_API`
  methods that should refresh tokens on failure
- decorate most endpoints with this *except* for the auth ep
- add locking logic for the troublesome scenario as follows:
  * every time a request is sent out set a "request in progress" event
    variable that can be used to determine when no requests are currently
    outstanding
  * every time the auth end point is hit in order to refresh tokens set
    an event that locks out other tasks from making requests
  * only allow hitting the auth endpoint when there are no "requests in
    progress" using the first event
  * mutex all auth endpoint requests; there can only be one outstanding

- don't hit the accounts endpoint at client startup; we want to
  eventually support keys from multiple accounts and you can disable
  account info per key and just share the market data function
2019-02-09 21:39:22 -05:00
Tyler Goodlet f6230dd6df Add a `DataFeed.call_client()` method
Allows for calling an actor local broker client's methods from a remote
actor.
2019-02-09 21:38:00 -05:00
Tyler Goodlet 026b015627 Allow passing a config path for broker testing in CI 2019-02-04 00:17:11 -05:00
Tyler Goodlet 5dac8fa44d Note the RH auth/account requirements for usage 2019-02-04 00:15:10 -05:00
Tyler Goodlet e91a50a1ba Make `get_cached_feed()` an asynccontextmanager
Adjust feed locking around internal manager `yields` to make this work.

Also, change quote publisher to deliver a list of quotes for each
retrieved batch. This was actually broken for option streaming since
each quote was being overwritten due to a common `key` value for all
expiries. Asjust the `packetizer` function accordingly to work for
both options and stocks.
2019-02-03 23:40:51 -05:00
Tyler Goodlet 2514843fc1 Port to the new `@tractor.msg.pub` decorator API
The pub-sub data feed system was factored into `tractor` as an
experimental api / subsystem. Move to using that which greatly
simplifies the data feed architecture.
2019-01-27 14:50:04 -05:00
Tyler Goodlet 22670afe58 Generalize the publisher/fan-out system
Start working toward a more general (on-demand) pub-sub system which
can be brought into ``tractor``. Right now this just means making
the code in the `fan_out_to_ctxs()` less specific but, eventually
I think this function should be coupled with a decorator and shipped
as a standard "message pattern".

Additionally,
- try out making `BrokerFeed` a `@dataclass`
- strip out all the `trio.Event` / uneeded nursery / extra task crap
  from `start_quote_stream()`
2019-01-14 21:23:49 -05:00
Tyler Goodlet c94ce47aa6 Always set contract sub state 2019-01-14 21:13:22 -05:00
Tyler Goodlet 4753dc2db8 Alway teardown quote gen on exit 2019-01-14 21:12:35 -05:00
Tyler Goodlet 36d0c2ed68 Port monitor app to `DataFeed` api 2019-01-05 19:08:31 -05:00
Tyler Goodlet a4501bb0e0 Factor `DataFeed` client API into `brokers.data` 2019-01-05 19:08:27 -05:00
Tyler Goodlet 7f8c88be0c Drop open/close prices for now; never really use them 2019-01-02 21:24:42 -05:00
Tyler Goodlet fa6bae1f5c Reorg table widgets into a new module 2019-01-02 21:12:42 -05:00
Tyler Goodlet 4895690642 Display a message when no contracts exist 2019-01-01 23:42:49 -05:00
Tyler Goodlet 0cffa4b97a Font size shrinks 2019-01-01 23:36:46 -05:00
Tyler Goodlet 32a7f4cbd3 Right, gotta expose widgets to other actors 2018-12-31 11:51:04 -05:00
Tyler Goodlet 72f417b9c2 Support monitor linked symbol selection
This allows for using a monitor to select the current option chain
symbol!

The deats:
- start a bg task which streams the monitor selected symbol
- dynamically repopulate expiry buttons on a newly published symbol
- move static widget creation into a chain method to avoid multiple
  quotes requests at startup
- rename a bunch of methods
2018-12-30 15:00:46 -05:00
Tyler Goodlet 152062ba8a Support pub-sub of monitor's symbol selection 2018-12-30 14:59:54 -05:00
Tyler Goodlet 3ed750d324 Add contract table type headers 2018-12-29 16:01:07 -05:00
Tyler Goodlet b4fad3f6a9 Logic factoring 2018-12-29 16:00:18 -05:00
Tyler Goodlet 1866dd1812 Fix for adjusted contracts subscription bug
If quotes are pushed using the adjusted contract symbol (i.e. with
trailing '-1' suffix) the subscriber won't receive them under the
normal symbol. The logic was wrong for determining whether to add
a suffix (was failing for any symbol with an exchange suffix)
which was causing normal data feed subscriptions to fail to match
in every case.

I did some testing of the `optionsIds` parameter to the option quote
endpoint and found that it limits you to 100 symbols so it's not
practical for real-time "all-strike"" chain updating; we have to stick
to filters for now. The only real downside of this is that it seems
multiple filters across multiple symbols is quite latent. I need to
toy with it more to be sure it's not something slow on the client side.
Oh, and store option contract to ids in a `dict` for now as we may want
to try the `optionsIds` thing again down the road as I coordinate with
the QT tech team.
2018-12-29 15:44:32 -05:00
Tyler Goodlet dc581d0bdc Handle "adjusted contract" chains per root 2018-12-26 13:30:50 -05:00
Tyler Goodlet fb876f3770 Drop `OptionChain.start_feed()` 2018-12-25 12:38:04 -05:00
Tyler Goodlet a7fb55179c Handle weekend data from QT yet again 2018-12-23 21:26:57 -05:00
Tyler Goodlet de4fab873b Ids should be allowed without contracts 2018-12-23 21:25:56 -05:00
Tyler Goodlet eb8c9e1a99 Symbol subs must be cid specific 2018-12-23 20:48:06 -05:00
Tyler Goodlet 11222e1176 Only resort when the sort field actually changed 2018-12-18 20:28:26 -05:00
Tyler Goodlet d4e36b1e55 Jeeze, don't overwrite the payload for each channel... 2018-12-17 19:15:29 -05:00
Tyler Goodlet 5af90c044f Drop contracts cache; that wasn't the bottleneck
This also fixes a bug where option subscriptions weren't actually being
changed when a new call was made..
2018-12-16 23:56:03 -05:00
Tyler Goodlet 3fd01c42f2 Define highlight on click logic in `Cell` 2018-12-15 19:42:15 -05:00
Tyler Goodlet 1f608b2498 Even less latent 2018-12-15 19:41:12 -05:00
Tyler Goodlet a13b13e144 Highlight current expiry; mutex data feed access 2018-12-15 19:40:54 -05:00
Tyler Goodlet 7ed409501d Even less bouncy 2018-12-15 16:38:33 -05:00
Tyler Goodlet 07eb8ae5e0 Use binary search (bisection) to sort table rows
This is an optimization to improve performance when the UI is fed real
time data. Instead of resorting all rows on every quote update, only
re-render when the sort key appears in the quote data, and further, only
resort rows which are changed using bisection based widget insertion to
avoid having `kivy` re-add widgets (and thus re-render graphics) more
often than absolutely necessary.
2018-12-15 16:28:28 -05:00
Tyler Goodlet 721e3803b2 Shorter title of IV: implied volatility 2018-12-15 16:27:41 -05:00
Tyler Goodlet 70435e3b15 Always push an option smoke quote for UI init 2018-12-15 16:26:54 -05:00
Tyler Goodlet e3a3a8765c Remove destroyed widgets from mouse over list 2018-12-15 16:26:21 -05:00
Tyler Goodlet 948ee3cadf Cache contracts lookup once at startup 2018-12-13 13:11:07 -05:00
Tyler Goodlet 9e4786e62f Initial dynamic option chain UI draft
There's still a ton to polish (and some bugs to fix) but this is a first
working draft of a real-time option chain!

Insights and todos:
- `kivy` widgets need to be cached and reused (eg. rows, cells, etc.)
  for speed since it seems creating new ones constantly is quite taxing
  on the CPU
- the chain will tear down and re-setup the option data feed stream each
  time a different contract expiry button set is clicked
- there's still some weird bug with row highlighting where it seems rows
  added from a new expiry set (which weren't previously rendered) aren't
  being highlighted reliably
2018-12-13 13:04:05 -05:00
Tyler Goodlet 743ca6bfe3 Log quotes even without caching 2018-12-11 17:09:59 -05:00
Tyler Goodlet 7b5c73bb45 Use pythonic sequence splitting with `zip()` 2018-12-11 17:09:36 -05:00
Tyler Goodlet e1be80e9e0 Subscription teardown is done server side on disconnect now 2018-12-11 15:22:34 -05:00
Tyler Goodlet e7378538f6 Limit option chain to 1 rps 2018-12-11 15:21:45 -05:00
Tyler Goodlet 66ecb4c0cb Use a `trio.Event` to guarantee respawning of data feed task 2018-12-11 15:21:12 -05:00
Tyler Goodlet 01c0551a7f Don't display greeks besides delta for now 2018-12-11 15:20:24 -05:00
Tyler Goodlet 201919eef7 Initial option chain UI
Spin it up with `piker optschain`.
Still lots of polishing and features to add but it's a start!
2018-12-10 02:00:10 -05:00
Tyler Goodlet 8647216b75 Tabular kivy UI improvements
`Row`:
- `no_cell`: support a list of keys for which no cells will be created
- allow passing in a `cell_type` at instantiation

`TickerTable`:
- keep track of rendered rows via a private `_rendered` set
- don't create rows inside `append_row()` expect caller to do it
- never render already rendered widgets in `render_rows()`

Miscellaneous:
- generalize `update_quotes()` to not be tied to specific quote fields
  and allow passing in a quote `formatter()` func
- don't bother creating a nursery block until necessary in main
- more commenting
2018-12-10 01:51:49 -05:00
Tyler Goodlet 20778b02b5 Format numerical option fields 2018-12-10 01:50:00 -05:00
Tyler Goodlet 54261ecc4c Refer to async exit stack via feed 2018-12-10 01:49:19 -05:00
Tyler Goodlet fb47ea2e5a Define option field structure
Add some extra fields to each quote that QT should already be
providing (instead of hiding them in the symbol and request contract
info); namely, the expiry and contact type (i.e. put or call).
Define the base set of fields to be displayed in an option chain
UI and add a quote formatter.
2018-12-09 13:40:26 -05:00
Tyler Goodlet 9c7ca84fef Include strike and expiry in option quotes 2018-12-09 13:40:26 -05:00
Tyler Goodlet 9f3a316ccf Improve CPU usage using a clock trigger and deque
Copy out `kivy.clock.triggered` from version 1.10.1 since it isn't yet
available in the `trio`/async branch and use it to throttle the callback
rate. Use a `collections.deque` to LIFO iterate widgets each call
using the heuristic that it's more likely the mouse is still within the
currently highlighted (or it's adjacent neighbors) widget as opposed
to some far away widget (the case when the mouse is moved very
drastically across the window).
2018-12-09 13:39:38 -05:00
Tyler Goodlet b8815cde4a Set statespace defaults in `get_cached_feed()` 2018-12-09 13:30:34 -05:00
Tyler Goodlet eee19048f0 Support "mouse over" groups
Add a type factory func which returns mixin-able types for creating
mutex highlight-able groups of widgets.
2018-12-01 19:01:36 -05:00
Tyler Goodlet fd94a24d84 Rename to `mouse_over` 2018-12-01 18:43:44 -05:00
Tyler Goodlet 5c070b1c43 Faster highlighting via single loop and callback
Thanks yet again to @tshirtman for suggesting this.

Instead of defining a `on_mouse_pos()` on every widget simply
register and track each widget and loop through them all once (or as much
as is necessary) in a single callback. The assumption here is that we
get a performance boost by looping widgets instead of having `kivy` loop
and call back each widget thus avoiding costly python function calls.
2018-12-01 18:39:01 -05:00
Tyler Goodlet 7378a16b90 s/tickers/symbols 2018-12-01 16:12:46 -05:00
Tyler Goodlet 2915e83324 Warn about missing symbols at CLI level 2018-12-01 16:11:38 -05:00
Tyler Goodlet 61294c6c44 Adhere to the same non-found-symbol behaviour as QT 2018-12-01 16:09:41 -05:00
Tyler Goodlet f35671cc88 Handle bad symbol names 2018-12-01 16:08:03 -05:00
Tyler Goodlet 288ea604af Call start_quote_stream() from monitor main 2018-11-30 08:17:54 -05:00
Tyler Goodlet c2ec4800d6 Port cli to new options api 2018-11-30 08:16:31 -05:00
Tyler Goodlet cabc616b85 Port option api to new backend broker api 2018-11-30 08:14:36 -05:00
Tyler Goodlet c7cf0cde9c Add options streaming
Well that was a doozy; had to rejig pretty much all of it.

The deats:
- Track broker components in a new `DataFeed` namedtuple
- port to new list based batch quotes (not dicts any more)
- lock access to cached broker-client / data-feed instantiation
- respawn tasks that fail due to the network
2018-11-30 08:13:30 -05:00