I'm trying to create a tool for analysing stock prices.
I've got a stream of price data for different stocks, and I want to have an observable to emit events whenever it receives a new, distinct and complete set of prices.
My plan: grouping the stream into different sub-streams for different stocks, and recombining their latest values.
Let's say I've got a stream of events like this:
from rx import Observable
stock_events = [
{'stock': 'A', 'price': 15},
{'stock': 'A', 'price': 16},
{'stock': 'B', 'price': 24},
{'stock': 'C', 'price': 37},
{'stock': 'A', 'price': 18},
{'stock': 'D', 'price': 42},
{'stock': 'B', 'price': 27},
{'stock': 'B', 'price': 27},
{'stock': 'C', 'price': 31},
{'stock': 'D', 'price': 44}
]
price_source = Observable.from_list(stock_events)
Here is my first (naive) approach:
a_source = price_source.filter(lambda x: x['stock'] == 'A').distinct_until_changed()
b_source = price_source.filter(lambda x: x['stock'] == 'B').distinct_until_changed()
c_source = price_source.filter(lambda x: x['stock'] == 'C').distinct_until_changed()
d_source = price_source.filter(lambda x: x['stock'] == 'D').distinct_until_changed()
(Observable
.combine_latest(a_source, b_source, c_source, d_source, lambda *x: x)
.subscribe(print))
This correctly gives me:
({'stock': 'A', 'price': 18}, {'stock': 'B', 'price': 24}, {'stock': 'C', 'price': 37}, {'stock': 'D', 'price': 42})
({'stock': 'A', 'price': 18}, {'stock': 'B', 'price': 27}, {'stock': 'C', 'price': 37}, {'stock': 'D', 'price': 42})
({'stock': 'A', 'price': 18}, {'stock': 'B', 'price': 27}, {'stock': 'C', 'price': 31}, {'stock': 'D', 'price': 42})
({'stock': 'A', 'price': 18}, {'stock': 'B', 'price': 27}, {'stock': 'C', 'price': 31}, {'stock': 'D', 'price': 44})
Yet, I feel that this should be better handled by group_by
, instead of several filterings, so here's a re-write:
(price_source
.group_by(lambda e: e['stock'])
.map(lambda obs: obs.distinct_until_changed())
.combine_latest(lambda *x: x)
.subscribe(print))
But this time, I get:
(<rx.core.anonymousobservable.AnonymousObservable object at 0x000000000105EA20>,)
(<rx.core.anonymousobservable.AnonymousObservable object at 0x000000000776AB00>,)
(<rx.core.anonymousobservable.AnonymousObservable object at 0x000000000776A438>,)
(<rx.core.anonymousobservable.AnonymousObservable object at 0x000000000775E7F0>,)
What have I missed here? How do I "unwrap" the nested observables?