From d2bc9c37651f8603dd956f45af298bb7bd6be615 Mon Sep 17 00:00:00 2001 From: Hardik Patel Date: Fri, 14 Sep 2018 17:08:41 -0400 Subject: [PATCH] Adding a slightly involved example with maps and lists --- grpc_advanced/README.md | 28 ++ grpc_advanced/client.py | 40 +++ grpc_advanced/market_data.proto | 35 +++ grpc_advanced/market_data_pb2.py | 413 ++++++++++++++++++++++++++ grpc_advanced/market_data_pb2_grpc.py | 47 +++ grpc_advanced/server.py | 67 +++++ 6 files changed, 630 insertions(+) create mode 100644 grpc_advanced/README.md create mode 100644 grpc_advanced/client.py create mode 100644 grpc_advanced/market_data.proto create mode 100644 grpc_advanced/market_data_pb2.py create mode 100644 grpc_advanced/market_data_pb2_grpc.py create mode 100644 grpc_advanced/server.py diff --git a/grpc_advanced/README.md b/grpc_advanced/README.md new file mode 100644 index 0000000..464521e --- /dev/null +++ b/grpc_advanced/README.md @@ -0,0 +1,28 @@ +# grpc demo + +* `MarketDataService` implements `GetOHLC` RPC call. +* `GetOHLC` takes in the list of stocks as well as the start and the end dates. +* `GetOHLC` returns the open, high, low, close prices for the given list of stocks. + +## How to Run + +1. Create an virtualenv and install requirements. + ```bash + cd grpc + pip3 install -r requirements.txt + ``` + +1. (Optional) Generate the compiled files. + ```bash + python -m grpc_tools.protoc --proto_path=. --python_out=. --grpc_python_out=. market_data.proto + ``` + +1. Run Server in one terminal window: + ```bash + python3 server.py + ``` + +1. Run Client in another terminal: + ```bash + python3 server.py + ``` \ No newline at end of file diff --git a/grpc_advanced/client.py b/grpc_advanced/client.py new file mode 100644 index 0000000..e720f88 --- /dev/null +++ b/grpc_advanced/client.py @@ -0,0 +1,40 @@ +from datetime import date + +import grpc +import pandas as pd + +import market_data_pb2 +import market_data_pb2_grpc + + +def run(): + channel = grpc.insecure_channel('localhost:50051') + stub = market_data_pb2_grpc.MarketDataStub(channel) + + stocks = ['TSLA', 'F', 'AAPL', 'MSFT', 'FB'] + start_date = date(2018, 1, 1).strftime('%Y-%m-%d') + end_date = date(2018, 9, 1).strftime('%Y-%m-%d') + + request = market_data_pb2.OHLCRequest(ticker=stocks, start_date=start_date, end_date=end_date) + + response = stub.GetOHLC(request) + + open_df = pd.DataFrame(index=response.dates) + high_df = pd.DataFrame(index=response.dates) + low_df = pd.DataFrame(index=response.dates) + close_df = pd.DataFrame(index=response.dates) + + for stock in response.open: + open_df[stock] = response.open[stock].price + high_df[stock] = response.high[stock].price + low_df[stock] = response.low[stock].price + close_df[stock] = response.close[stock].price + + print('Last day Open: ') + print(open_df.tail(1)) + print('Last day Close: ') + print(close_df.tail(1)) + + +if __name__ == '__main__': + run() diff --git a/grpc_advanced/market_data.proto b/grpc_advanced/market_data.proto new file mode 100644 index 0000000..f453333 --- /dev/null +++ b/grpc_advanced/market_data.proto @@ -0,0 +1,35 @@ +syntax = "proto3"; +package market_data; + +message OHLCRequest { + // List of stocks + repeated string ticker = 3; + + // Start date + string start_date = 1; + + // End date + string end_date = 2; +} + +message OHLCReply { + // OHLCRet + message OHLCRet { + // Stock price list + repeated double price = 1; + } + + // List of dates + repeated string dates = 1; + + map open = 2; + map high = 3; + map low = 4; + map close = 5; +} + +service MarketData { + // Get the [Open, High, Low, Close] for the given list of stocks + // and start/end dates + rpc GetOHLC(OHLCRequest) returns (OHLCReply); +} diff --git a/grpc_advanced/market_data_pb2.py b/grpc_advanced/market_data_pb2.py new file mode 100644 index 0000000..6ee9c2d --- /dev/null +++ b/grpc_advanced/market_data_pb2.py @@ -0,0 +1,413 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: market_data.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='market_data.proto', + package='market_data', + syntax='proto3', + serialized_pb=_b('\n\x11market_data.proto\x12\x0bmarket_data\"C\n\x0bOHLCRequest\x12\x0e\n\x06ticker\x18\x03 \x03(\t\x12\x12\n\nstart_date\x18\x01 \x01(\t\x12\x10\n\x08\x65nd_date\x18\x02 \x01(\t\"\xa8\x04\n\tOHLCReply\x12\r\n\x05\x64\x61tes\x18\x01 \x03(\t\x12.\n\x04open\x18\x02 \x03(\x0b\x32 .market_data.OHLCReply.OpenEntry\x12.\n\x04high\x18\x03 \x03(\x0b\x32 .market_data.OHLCReply.HighEntry\x12,\n\x03low\x18\x04 \x03(\x0b\x32\x1f.market_data.OHLCReply.LowEntry\x12\x30\n\x05\x63lose\x18\x05 \x03(\x0b\x32!.market_data.OHLCReply.CloseEntry\x1a\x18\n\x07OHLCRet\x12\r\n\x05price\x18\x01 \x03(\x01\x1aK\n\tOpenEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12-\n\x05value\x18\x02 \x01(\x0b\x32\x1e.market_data.OHLCReply.OHLCRet:\x02\x38\x01\x1aK\n\tHighEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12-\n\x05value\x18\x02 \x01(\x0b\x32\x1e.market_data.OHLCReply.OHLCRet:\x02\x38\x01\x1aJ\n\x08LowEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12-\n\x05value\x18\x02 \x01(\x0b\x32\x1e.market_data.OHLCReply.OHLCRet:\x02\x38\x01\x1aL\n\nCloseEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12-\n\x05value\x18\x02 \x01(\x0b\x32\x1e.market_data.OHLCReply.OHLCRet:\x02\x38\x01\x32I\n\nMarketData\x12;\n\x07GetOHLC\x12\x18.market_data.OHLCRequest\x1a\x16.market_data.OHLCReplyb\x06proto3') +) + + + + +_OHLCREQUEST = _descriptor.Descriptor( + name='OHLCRequest', + full_name='market_data.OHLCRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ticker', full_name='market_data.OHLCRequest.ticker', index=0, + number=3, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='start_date', full_name='market_data.OHLCRequest.start_date', index=1, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='end_date', full_name='market_data.OHLCRequest.end_date', index=2, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=34, + serialized_end=101, +) + + +_OHLCREPLY_OHLCRET = _descriptor.Descriptor( + name='OHLCRet', + full_name='market_data.OHLCReply.OHLCRet', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='price', full_name='market_data.OHLCReply.OHLCRet.price', index=0, + number=1, type=1, cpp_type=5, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=324, + serialized_end=348, +) + +_OHLCREPLY_OPENENTRY = _descriptor.Descriptor( + name='OpenEntry', + full_name='market_data.OHLCReply.OpenEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='market_data.OHLCReply.OpenEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='market_data.OHLCReply.OpenEntry.value', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=350, + serialized_end=425, +) + +_OHLCREPLY_HIGHENTRY = _descriptor.Descriptor( + name='HighEntry', + full_name='market_data.OHLCReply.HighEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='market_data.OHLCReply.HighEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='market_data.OHLCReply.HighEntry.value', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=427, + serialized_end=502, +) + +_OHLCREPLY_LOWENTRY = _descriptor.Descriptor( + name='LowEntry', + full_name='market_data.OHLCReply.LowEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='market_data.OHLCReply.LowEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='market_data.OHLCReply.LowEntry.value', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=504, + serialized_end=578, +) + +_OHLCREPLY_CLOSEENTRY = _descriptor.Descriptor( + name='CloseEntry', + full_name='market_data.OHLCReply.CloseEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='market_data.OHLCReply.CloseEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='market_data.OHLCReply.CloseEntry.value', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=580, + serialized_end=656, +) + +_OHLCREPLY = _descriptor.Descriptor( + name='OHLCReply', + full_name='market_data.OHLCReply', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='dates', full_name='market_data.OHLCReply.dates', index=0, + number=1, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='open', full_name='market_data.OHLCReply.open', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='high', full_name='market_data.OHLCReply.high', index=2, + number=3, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='low', full_name='market_data.OHLCReply.low', index=3, + number=4, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='close', full_name='market_data.OHLCReply.close', index=4, + number=5, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[_OHLCREPLY_OHLCRET, _OHLCREPLY_OPENENTRY, _OHLCREPLY_HIGHENTRY, _OHLCREPLY_LOWENTRY, _OHLCREPLY_CLOSEENTRY, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=104, + serialized_end=656, +) + +_OHLCREPLY_OHLCRET.containing_type = _OHLCREPLY +_OHLCREPLY_OPENENTRY.fields_by_name['value'].message_type = _OHLCREPLY_OHLCRET +_OHLCREPLY_OPENENTRY.containing_type = _OHLCREPLY +_OHLCREPLY_HIGHENTRY.fields_by_name['value'].message_type = _OHLCREPLY_OHLCRET +_OHLCREPLY_HIGHENTRY.containing_type = _OHLCREPLY +_OHLCREPLY_LOWENTRY.fields_by_name['value'].message_type = _OHLCREPLY_OHLCRET +_OHLCREPLY_LOWENTRY.containing_type = _OHLCREPLY +_OHLCREPLY_CLOSEENTRY.fields_by_name['value'].message_type = _OHLCREPLY_OHLCRET +_OHLCREPLY_CLOSEENTRY.containing_type = _OHLCREPLY +_OHLCREPLY.fields_by_name['open'].message_type = _OHLCREPLY_OPENENTRY +_OHLCREPLY.fields_by_name['high'].message_type = _OHLCREPLY_HIGHENTRY +_OHLCREPLY.fields_by_name['low'].message_type = _OHLCREPLY_LOWENTRY +_OHLCREPLY.fields_by_name['close'].message_type = _OHLCREPLY_CLOSEENTRY +DESCRIPTOR.message_types_by_name['OHLCRequest'] = _OHLCREQUEST +DESCRIPTOR.message_types_by_name['OHLCReply'] = _OHLCREPLY +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +OHLCRequest = _reflection.GeneratedProtocolMessageType('OHLCRequest', (_message.Message,), dict( + DESCRIPTOR = _OHLCREQUEST, + __module__ = 'market_data_pb2' + # @@protoc_insertion_point(class_scope:market_data.OHLCRequest) + )) +_sym_db.RegisterMessage(OHLCRequest) + +OHLCReply = _reflection.GeneratedProtocolMessageType('OHLCReply', (_message.Message,), dict( + + OHLCRet = _reflection.GeneratedProtocolMessageType('OHLCRet', (_message.Message,), dict( + DESCRIPTOR = _OHLCREPLY_OHLCRET, + __module__ = 'market_data_pb2' + # @@protoc_insertion_point(class_scope:market_data.OHLCReply.OHLCRet) + )) + , + + OpenEntry = _reflection.GeneratedProtocolMessageType('OpenEntry', (_message.Message,), dict( + DESCRIPTOR = _OHLCREPLY_OPENENTRY, + __module__ = 'market_data_pb2' + # @@protoc_insertion_point(class_scope:market_data.OHLCReply.OpenEntry) + )) + , + + HighEntry = _reflection.GeneratedProtocolMessageType('HighEntry', (_message.Message,), dict( + DESCRIPTOR = _OHLCREPLY_HIGHENTRY, + __module__ = 'market_data_pb2' + # @@protoc_insertion_point(class_scope:market_data.OHLCReply.HighEntry) + )) + , + + LowEntry = _reflection.GeneratedProtocolMessageType('LowEntry', (_message.Message,), dict( + DESCRIPTOR = _OHLCREPLY_LOWENTRY, + __module__ = 'market_data_pb2' + # @@protoc_insertion_point(class_scope:market_data.OHLCReply.LowEntry) + )) + , + + CloseEntry = _reflection.GeneratedProtocolMessageType('CloseEntry', (_message.Message,), dict( + DESCRIPTOR = _OHLCREPLY_CLOSEENTRY, + __module__ = 'market_data_pb2' + # @@protoc_insertion_point(class_scope:market_data.OHLCReply.CloseEntry) + )) + , + DESCRIPTOR = _OHLCREPLY, + __module__ = 'market_data_pb2' + # @@protoc_insertion_point(class_scope:market_data.OHLCReply) + )) +_sym_db.RegisterMessage(OHLCReply) +_sym_db.RegisterMessage(OHLCReply.OHLCRet) +_sym_db.RegisterMessage(OHLCReply.OpenEntry) +_sym_db.RegisterMessage(OHLCReply.HighEntry) +_sym_db.RegisterMessage(OHLCReply.LowEntry) +_sym_db.RegisterMessage(OHLCReply.CloseEntry) + + +_OHLCREPLY_OPENENTRY.has_options = True +_OHLCREPLY_OPENENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) +_OHLCREPLY_HIGHENTRY.has_options = True +_OHLCREPLY_HIGHENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) +_OHLCREPLY_LOWENTRY.has_options = True +_OHLCREPLY_LOWENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) +_OHLCREPLY_CLOSEENTRY.has_options = True +_OHLCREPLY_CLOSEENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) + +_MARKETDATA = _descriptor.ServiceDescriptor( + name='MarketData', + full_name='market_data.MarketData', + file=DESCRIPTOR, + index=0, + options=None, + serialized_start=658, + serialized_end=731, + methods=[ + _descriptor.MethodDescriptor( + name='GetOHLC', + full_name='market_data.MarketData.GetOHLC', + index=0, + containing_service=None, + input_type=_OHLCREQUEST, + output_type=_OHLCREPLY, + options=None, + ), +]) +_sym_db.RegisterServiceDescriptor(_MARKETDATA) + +DESCRIPTOR.services_by_name['MarketData'] = _MARKETDATA + +# @@protoc_insertion_point(module_scope) diff --git a/grpc_advanced/market_data_pb2_grpc.py b/grpc_advanced/market_data_pb2_grpc.py new file mode 100644 index 0000000..4cb8b56 --- /dev/null +++ b/grpc_advanced/market_data_pb2_grpc.py @@ -0,0 +1,47 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +import grpc + +import market_data_pb2 as market__data__pb2 + + +class MarketDataStub(object): + # missing associated documentation comment in .proto file + pass + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetOHLC = channel.unary_unary( + '/market_data.MarketData/GetOHLC', + request_serializer=market__data__pb2.OHLCRequest.SerializeToString, + response_deserializer=market__data__pb2.OHLCReply.FromString, + ) + + +class MarketDataServicer(object): + # missing associated documentation comment in .proto file + pass + + def GetOHLC(self, request, context): + """Get the [Open, High, Low, Close] for the given list of stocks + and start/end dates + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_MarketDataServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetOHLC': grpc.unary_unary_rpc_method_handler( + servicer.GetOHLC, + request_deserializer=market__data__pb2.OHLCRequest.FromString, + response_serializer=market__data__pb2.OHLCReply.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'market_data.MarketData', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) diff --git a/grpc_advanced/server.py b/grpc_advanced/server.py new file mode 100644 index 0000000..556bd99 --- /dev/null +++ b/grpc_advanced/server.py @@ -0,0 +1,67 @@ +import time +from concurrent import futures +from datetime import datetime + +import grpc +import pandas_datareader.data as web + +import market_data_pb2 +import market_data_pb2_grpc + +_ONE_DAY_IN_SECONDS = 60 * 60 * 24 + + +class MarketDataService(market_data_pb2_grpc.MarketDataServicer): + """ + MarketDataService + - GetOHLC - returns the open, high, low, close prices for the given securities. + """ + + def GetOHLC(self, request, context): + """ + Returns [open, high, low, close] prices for the given list of securities. + Prices are specified between given start and end dates. + """ + # Extract arguments + start_date = datetime.strptime(request.start_date, '%Y-%m-%d').date() + end_date = datetime.strptime(request.end_date, '%Y-%m-%d').date() + tickers = request.ticker + + # Reply parameters + open_dict = {} + high_dict = {} + low_dict = {} + close_dict = {} + dates = None + + # Fetch OHLC data using pandas-datareader + for ticker in tickers: + df = web.DataReader(ticker, 'iex', start_date, end_date) + + if dates is None: + dates = list(df.index) + + open_dict[ticker] = market_data_pb2.OHLCReply.OHLCRet(price=list(df['open'])) + high_dict[ticker] = market_data_pb2.OHLCReply.OHLCRet(price=list(df['high'])) + low_dict[ticker] = market_data_pb2.OHLCReply.OHLCRet(price=list(df['low'])) + close_dict[ticker] = market_data_pb2.OHLCReply.OHLCRet(price=list(df['close'])) + + # Construct the OHLC Reply + reply = market_data_pb2.OHLCReply(dates=dates, open=open_dict, high=high_dict, low=low_dict, close=close_dict) + return reply + + +def serve(): + server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) + market_data_pb2_grpc.add_MarketDataServicer_to_server(MarketDataService(), server) + server.add_insecure_port('[::]:50051') + server.start() + try: + while True: + time.sleep(_ONE_DAY_IN_SECONDS) + except KeyboardInterrupt: + server.stop(0) + + +if __name__ == '__main__': + serve()