Feature Store Example (Stocks)

This notebook demonstrates the following:

  • Generate features and feature-sets

  • Build complex transformations and ingest to offline and real-time data stores

  • Fetch feature vectors for training

  • Save feature vectors for re-use in real-time pipelines

  • Access features and their statistics in real-time

Install the latest MLRun package and restart the notebook

Setting up the environment and project

import mlrun
mlrun.set_environment(project="stocks")
> 2021-05-23 09:04:04,507 [warning] Failed resolving version info. Ignoring and using defaults
> 2021-05-23 09:04:07,033 [warning] Unable to parse server or client version. Assuming compatible: {'server_version': '0.6.4-rc3', 'client_version': 'unstable'}
('stocks', 'v3io:///projects/{{run.project}}/artifacts')

Create Sample Data For Demo

import pandas as pd
quotes = pd.DataFrame(
    {
        "time": [
            pd.Timestamp("2016-05-25 13:30:00.023"),
            pd.Timestamp("2016-05-25 13:30:00.023"),
            pd.Timestamp("2016-05-25 13:30:00.030"),
            pd.Timestamp("2016-05-25 13:30:00.041"),
            pd.Timestamp("2016-05-25 13:30:00.048"),
            pd.Timestamp("2016-05-25 13:30:00.049"),
            pd.Timestamp("2016-05-25 13:30:00.072"),
            pd.Timestamp("2016-05-25 13:30:00.075")
        ],
        "ticker": [
               "GOOG",
               "MSFT",
               "MSFT",
               "MSFT",
               "GOOG",
               "AAPL",
               "GOOG",
               "MSFT"
           ],
           "bid": [720.50, 51.95, 51.97, 51.99, 720.50, 97.99, 720.50, 52.01],
           "ask": [720.93, 51.96, 51.98, 52.00, 720.93, 98.01, 720.88, 52.03]
    }
)

trades = pd.DataFrame(
       {
           "time": [
               pd.Timestamp("2016-05-25 13:30:00.023"),
               pd.Timestamp("2016-05-25 13:30:00.038"),
               pd.Timestamp("2016-05-25 13:30:00.048"),
               pd.Timestamp("2016-05-25 13:30:00.048"),
               pd.Timestamp("2016-05-25 13:30:00.048")
           ],
           "ticker": ["MSFT", "MSFT", "GOOG", "GOOG", "AAPL"],
           "price": [51.95, 51.95, 720.77, 720.92, 98.0],
           "quantity": [75, 155, 100, 100, 100]
       }
)


stocks = pd.DataFrame(
       {
           "ticker": ["MSFT", "GOOG", "AAPL"],
           "name": ["Microsoft Corporation", "Alphabet Inc", "Apple Inc"],
           "exchange": ["NASDAQ", "NASDAQ", "NASDAQ"]
       }
)

import datetime
def move_date(df, col):
    max_date = df[col].max()
    now_date = datetime.datetime.now()
    delta = now_date - max_date 
    df[col] = df[col] + delta 
    return df

quotes = move_date(quotes, "time")
trades = move_date(trades, "time")

View Demo Data

quotes
time ticker bid ask
0 2021-05-23 09:04:07.013574 GOOG 720.50 720.93
1 2021-05-23 09:04:07.013574 MSFT 51.95 51.96
2 2021-05-23 09:04:07.020574 MSFT 51.97 51.98
3 2021-05-23 09:04:07.031574 MSFT 51.99 52.00
4 2021-05-23 09:04:07.038574 GOOG 720.50 720.93
5 2021-05-23 09:04:07.039574 AAPL 97.99 98.01
6 2021-05-23 09:04:07.062574 GOOG 720.50 720.88
7 2021-05-23 09:04:07.065574 MSFT 52.01 52.03
trades
time ticker price quantity
0 2021-05-23 09:04:07.041766 MSFT 51.95 75
1 2021-05-23 09:04:07.056766 MSFT 51.95 155
2 2021-05-23 09:04:07.066766 GOOG 720.77 100
3 2021-05-23 09:04:07.066766 GOOG 720.92 100
4 2021-05-23 09:04:07.066766 AAPL 98.00 100
stocks
ticker name exchange
0 MSFT Microsoft Corporation NASDAQ
1 GOOG Alphabet Inc NASDAQ
2 AAPL Apple Inc NASDAQ

Define, Infer and Ingest Feature Sets

import mlrun.feature_store as fstore
from mlrun.feature_store.steps import *
from mlrun.features import MinMaxValidator

Build & Ingest Simple Feature Set (stocks)

# add feature set without time column (stock ticker metadata) 
stocks_set = fstore.FeatureSet("stocks", entities=[fstore.Entity("ticker")])
fstore.ingest(stocks_set, stocks, infer_options=fstore.InferOptions.default())
name exchange
ticker
MSFT Microsoft Corporation NASDAQ
GOOG Alphabet Inc NASDAQ
AAPL Apple Inc NASDAQ

Build Advanced feature set - with feature engineering pipeline

Define a feature set with custom data processing and time aggregation functions

# create a new feature set
quotes_set = fstore.FeatureSet("stock-quotes", entities=[fstore.Entity("ticker")])

define a custom pipeline step (python class)

class MyMap(MapClass):
    def __init__(self, multiplier=1, **kwargs):
        super().__init__(**kwargs)
        self._multiplier = multiplier

    def do(self, event):
        event["multi"] = event["bid"] * self._multiplier
        return event

build and show the transformatiom pipeline

Use storey stream processing classes along with library and custom classes

quotes_set.graph.to("MyMap", multiplier=3)\
                .to("storey.Extend", _fn="({'extra': event['bid'] * 77})")\
                .to("storey.Filter", "filter", _fn="(event['bid'] > 51.92)")\
                .to(FeaturesetValidator())

quotes_set.add_aggregation("asks1", "ask", ["sum", "max"], "1h", "10m")
quotes_set.add_aggregation("asks5", "ask", ["sum", "max"], "5h", "10m")
quotes_set.add_aggregation("bids", "bid", ["min", "max"], "1h", "10m")

# add feature validation policy
quotes_set["bid"] = fstore.Feature(validator=MinMaxValidator(min=52, severity="info"))

# add default target definitions and plot
quotes_set.set_targets()
quotes_set.plot(rankdir="LR", with_targets=True)
../_images/basic-demo_17_0.svg

test and show the pipeline results locally (allow to quickly develop and debug)

fstore.preview(
    quotes_set,
    quotes,
    entity_columns=["ticker"],
    timestamp_key="time",
    options=fstore.InferOptions.default(),
)
info! bid value is smaller than min, key=['MSFT'] time=2021-05-23 09:04:07.013574 args={'min': 52, 'value': 51.95}
info! bid value is smaller than min, key=['MSFT'] time=2021-05-23 09:04:07.020574 args={'min': 52, 'value': 51.97}
info! bid value is smaller than min, key=['MSFT'] time=2021-05-23 09:04:07.031574 args={'min': 52, 'value': 51.99}
asks1_sum_1h asks1_max_1h asks5_sum_5h asks5_max_5h bids_min_1h bids_max_1h time bid ask multi extra
ticker
GOOG 720.93 720.93 720.93 720.93 720.50 720.50 2021-05-23 09:04:07.013574 720.50 720.93 2161.50 55478.50
MSFT 51.96 51.96 51.96 51.96 51.95 51.95 2021-05-23 09:04:07.013574 51.95 51.96 155.85 4000.15
MSFT 103.94 51.98 103.94 51.98 51.95 51.97 2021-05-23 09:04:07.020574 51.97 51.98 155.91 4001.69
MSFT 155.94 52.00 155.94 52.00 51.95 51.99 2021-05-23 09:04:07.031574 51.99 52.00 155.97 4003.23
GOOG 1441.86 720.93 1441.86 720.93 720.50 720.50 2021-05-23 09:04:07.038574 720.50 720.93 2161.50 55478.50
AAPL 98.01 98.01 98.01 98.01 97.99 97.99 2021-05-23 09:04:07.039574 97.99 98.01 293.97 7545.23
GOOG 2162.74 720.93 2162.74 720.93 720.50 720.50 2021-05-23 09:04:07.062574 720.50 720.88 2161.50 55478.50
MSFT 207.97 52.03 207.97 52.03 51.95 52.01 2021-05-23 09:04:07.065574 52.01 52.03 156.03 4004.77
# print the feature set object
print(quotes_set.to_yaml())
kind: FeatureSet
metadata:
  name: stock-quotes
spec:
  entities:
  - name: ticker
    value_type: str
  features:
  - name: asks1_sum_1h
    value_type: float
    aggregate: true
  - name: asks1_max_1h
    value_type: float
    aggregate: true
  - name: asks5_sum_5h
    value_type: float
    aggregate: true
  - name: asks5_max_5h
    value_type: float
    aggregate: true
  - name: bids_min_1h
    value_type: float
    aggregate: true
  - name: bids_max_1h
    value_type: float
    aggregate: true
  - name: bid
    value_type: float
    validator:
      kind: minmax
      severity: info
      min: 52
  - name: ask
    value_type: float
  - name: multi
    value_type: float
  - name: extra
    value_type: float
  partition_keys: []
  timestamp_key: time
  source:
    path: None
  targets:
  - name: parquet
    kind: parquet
  - name: nosql
    kind: nosql
  graph:
    states:
      MyMap:
        kind: task
        class_name: MyMap
        class_args:
          multiplier: 3
      storey.Extend:
        kind: task
        class_name: storey.Extend
        class_args:
          _fn: '({''extra'': event[''bid''] * 77})'
        after:
        - MyMap
      filter:
        kind: task
        class_name: storey.Filter
        class_args:
          _fn: (event['bid'] > 51.92)
        after:
        - storey.Extend
      FeaturesetValidator:
        kind: task
        class_name: mlrun.feature_store.steps.FeaturesetValidator
        class_args:
          featureset: .
          columns: null
        after:
        - filter
      Aggregates:
        kind: task
        class_name: storey.AggregateByKey
        class_args:
          aggregates:
          - name: asks1
            column: ask
            operations:
            - sum
            - max
            windows:
            - 1h
            period: 10m
          - name: asks5
            column: ask
            operations:
            - sum
            - max
            windows:
            - 5h
            period: 10m
          - name: bids
            column: bid
            operations:
            - min
            - max
            windows:
            - 1h
            period: 10m
          table: .
        after:
        - FeaturesetValidator
  output_path: v3io:///projects/{{run.project}}/artifacts
status:
  state: created
  stats:
    ticker:
      count: 8
      unique: 3
      top: MSFT
      freq: 4
    asks1_sum_1h:
      count: 8.0
      mean: 617.9187499999999
      min: 51.96
      max: 2162.74
      std: 784.8779804245735
      hist:
      - - 4
        - 1
        - 0
        - 0
        - 0
        - 0
        - 1
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 1
        - 0
        - 0
        - 0
        - 0
        - 0
        - 1
      - - 51.96
        - 157.499
        - 263.03799999999995
        - 368.57699999999994
        - 474.11599999999993
        - 579.655
        - 685.194
        - 790.733
        - 896.2719999999999
        - 1001.8109999999999
        - 1107.35
        - 1212.889
        - 1318.4279999999999
        - 1423.9669999999999
        - 1529.5059999999999
        - 1635.0449999999998
        - 1740.5839999999998
        - 1846.1229999999998
        - 1951.6619999999998
        - 2057.2009999999996
        - 2162.74
    asks1_max_1h:
      count: 8.0
      mean: 308.59625
      min: 51.96
      max: 720.93
      std: 341.7989955655851
      hist:
      - - 4
        - 1
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 3
      - - 51.96
        - 85.4085
        - 118.857
        - 152.3055
        - 185.754
        - 219.2025
        - 252.65099999999998
        - 286.0995
        - 319.54799999999994
        - 352.9964999999999
        - 386.44499999999994
        - 419.89349999999996
        - 453.3419999999999
        - 486.7904999999999
        - 520.2389999999999
        - 553.6875
        - 587.136
        - 620.5844999999999
        - 654.0329999999999
        - 687.4815
        - 720.93
    asks5_sum_5h:
      count: 8.0
      mean: 617.9187499999999
      min: 51.96
      max: 2162.74
      std: 784.8779804245735
      hist:
      - - 4
        - 1
        - 0
        - 0
        - 0
        - 0
        - 1
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 1
        - 0
        - 0
        - 0
        - 0
        - 0
        - 1
      - - 51.96
        - 157.499
        - 263.03799999999995
        - 368.57699999999994
        - 474.11599999999993
        - 579.655
        - 685.194
        - 790.733
        - 896.2719999999999
        - 1001.8109999999999
        - 1107.35
        - 1212.889
        - 1318.4279999999999
        - 1423.9669999999999
        - 1529.5059999999999
        - 1635.0449999999998
        - 1740.5839999999998
        - 1846.1229999999998
        - 1951.6619999999998
        - 2057.2009999999996
        - 2162.74
    asks5_max_5h:
      count: 8.0
      mean: 308.59625
      min: 51.96
      max: 720.93
      std: 341.7989955655851
      hist:
      - - 4
        - 1
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 3
      - - 51.96
        - 85.4085
        - 118.857
        - 152.3055
        - 185.754
        - 219.2025
        - 252.65099999999998
        - 286.0995
        - 319.54799999999994
        - 352.9964999999999
        - 386.44499999999994
        - 419.89349999999996
        - 453.3419999999999
        - 486.7904999999999
        - 520.2389999999999
        - 553.6875
        - 587.136
        - 620.5844999999999
        - 654.0329999999999
        - 687.4815
        - 720.93
    bids_min_1h:
      count: 8.0
      mean: 308.41125
      min: 51.95
      max: 720.5
      std: 341.59667259325835
      hist:
      - - 4
        - 1
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 3
      - - 51.95
        - 85.3775
        - 118.80499999999999
        - 152.2325
        - 185.65999999999997
        - 219.08749999999998
        - 252.515
        - 285.94249999999994
        - 319.36999999999995
        - 352.79749999999996
        - 386.22499999999997
        - 419.6524999999999
        - 453.0799999999999
        - 486.50749999999994
        - 519.935
        - 553.3625
        - 586.79
        - 620.2175
        - 653.645
        - 687.0725
        - 720.5
    bids_max_1h:
      count: 8.0
      mean: 308.42625
      min: 51.95
      max: 720.5
      std: 341.58380276661245
      hist:
      - - 4
        - 1
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 3
      - - 51.95
        - 85.3775
        - 118.80499999999999
        - 152.2325
        - 185.65999999999997
        - 219.08749999999998
        - 252.515
        - 285.94249999999994
        - 319.36999999999995
        - 352.79749999999996
        - 386.22499999999997
        - 419.6524999999999
        - 453.0799999999999
        - 486.50749999999994
        - 519.935
        - 553.3625
        - 586.79
        - 620.2175
        - 653.645
        - 687.0725
        - 720.5
    time:
      count: 8
      mean: '2021-05-23 09:04:07.035699200'
      min: '2021-05-23 09:04:07.013574'
      max: '2021-05-23 09:04:07.065574'
    bid:
      count: 8.0
      mean: 308.42625
      min: 51.95
      max: 720.5
      std: 341.58380276661245
      hist:
      - - 4
        - 1
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 3
      - - 51.95
        - 85.3775
        - 118.80499999999999
        - 152.2325
        - 185.65999999999997
        - 219.08749999999998
        - 252.515
        - 285.94249999999994
        - 319.36999999999995
        - 352.79749999999996
        - 386.22499999999997
        - 419.6524999999999
        - 453.0799999999999
        - 486.50749999999994
        - 519.935
        - 553.3625
        - 586.79
        - 620.2175
        - 653.645
        - 687.0725
        - 720.5
    ask:
      count: 8.0
      mean: 308.59
      min: 51.96
      max: 720.93
      std: 341.79037903369954
      hist:
      - - 4
        - 1
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 3
      - - 51.96
        - 85.4085
        - 118.857
        - 152.3055
        - 185.754
        - 219.2025
        - 252.65099999999998
        - 286.0995
        - 319.54799999999994
        - 352.9964999999999
        - 386.44499999999994
        - 419.89349999999996
        - 453.3419999999999
        - 486.7904999999999
        - 520.2389999999999
        - 553.6875
        - 587.136
        - 620.5844999999999
        - 654.0329999999999
        - 687.4815
        - 720.93
    multi:
      count: 8.0
      mean: 925.27875
      min: 155.85000000000002
      max: 2161.5
      std: 1024.7514082998375
      hist:
      - - 4
        - 1
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 3
      - - 155.85000000000002
        - 256.13250000000005
        - 356.415
        - 456.6975
        - 556.98
        - 657.2625
        - 757.545
        - 857.8275
        - 958.11
        - 1058.3925
        - 1158.6750000000002
        - 1258.9575
        - 1359.2399999999998
        - 1459.5225
        - 1559.8049999999998
        - 1660.0875
        - 1760.37
        - 1860.6525000000001
        - 1960.935
        - 2061.2175
        - 2161.5
    extra:
      count: 8.0
      mean: 23748.82125
      min: 4000.15
      max: 55478.5
      std: 26301.95281302916
      hist:
      - - 4
        - 1
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 0
        - 3
      - - 4000.15
        - 6574.0675
        - 9147.985
        - 11721.9025
        - 14295.82
        - 16869.7375
        - 19443.655000000002
        - 22017.572500000002
        - 24591.49
        - 27165.4075
        - 29739.325
        - 32313.2425
        - 34887.16
        - 37461.0775
        - 40034.995
        - 42608.9125
        - 45182.83
        - 47756.747500000005
        - 50330.665
        - 52904.582500000004
        - 55478.5
  preview:
  - - asks1_sum_1h
    - asks1_max_1h
    - asks5_sum_5h
    - asks5_max_5h
    - bids_min_1h
    - bids_max_1h
    - time
    - bid
    - ask
    - multi
    - extra
  - - 720.93
    - 720.93
    - 720.93
    - 720.93
    - 720.5
    - 720.5
    - 2021-05-23T09:04:07.013574
    - 720.5
    - 720.93
    - 2161.5
    - 55478.5
  - - 51.96
    - 51.96
    - 51.96
    - 51.96
    - 51.95
    - 51.95
    - 2021-05-23T09:04:07.013574
    - 51.95
    - 51.96
    - 155.85000000000002
    - 4000.15
  - - 103.94
    - 51.98
    - 103.94
    - 51.98
    - 51.95
    - 51.97
    - 2021-05-23T09:04:07.020574
    - 51.97
    - 51.98
    - 155.91
    - 4001.69
  - - 155.94
    - 52.0
    - 155.94
    - 52.0
    - 51.95
    - 51.99
    - 2021-05-23T09:04:07.031574
    - 51.99
    - 52.0
    - 155.97
    - 4003.23
  - - 1441.86
    - 720.93
    - 1441.86
    - 720.93
    - 720.5
    - 720.5
    - 2021-05-23T09:04:07.038574
    - 720.5
    - 720.93
    - 2161.5
    - 55478.5
  - - 98.01
    - 98.01
    - 98.01
    - 98.01
    - 97.99
    - 97.99
    - 2021-05-23T09:04:07.039574
    - 97.99
    - 98.01
    - 293.96999999999997
    - 7545.23
  - - 2162.74
    - 720.93
    - 2162.74
    - 720.93
    - 720.5
    - 720.5
    - 2021-05-23T09:04:07.062574
    - 720.5
    - 720.88
    - 2161.5
    - 55478.5
  - - 207.97
    - 52.03
    - 207.97
    - 52.03
    - 51.95
    - 52.01
    - 2021-05-23T09:04:07.065574
    - 52.01
    - 52.03
    - 156.03
    - 4004.77

ingest data into offline and online stores

This will write to both targets (Parquet and NoSQL)

# save ingest data and print the FeatureSet spec
df = fstore.ingest(quotes_set, quotes)
info! bid value is smaller than min, key=['MSFT'] time=2021-05-23 09:04:07.013574 args={'min': 52, 'value': 51.95}
info! bid value is smaller than min, key=['MSFT'] time=2021-05-23 09:04:07.020574 args={'min': 52, 'value': 51.97}
info! bid value is smaller than min, key=['MSFT'] time=2021-05-23 09:04:07.031574 args={'min': 52, 'value': 51.99}
info! bid value is smaller than min, key=['MSFT'] time=2021-05-23 09:04:07.013574 args={'min': 52, 'value': 51.95}
info! bid value is smaller than min, key=['MSFT'] time=2021-05-23 09:04:07.020574 args={'min': 52, 'value': 51.97}
info! bid value is smaller than min, key=['MSFT'] time=2021-05-23 09:04:07.031574 args={'min': 52, 'value': 51.99}

Get an Offline Feature Vector for Training

Example of combining features from 3 sources with time travel join of 3 tables with time travel

Specify a set of features and request the feature vector offline result as a dataframe

features = [
    "stock-quotes.multi",
    "stock-quotes.asks5_sum_5h as total_ask",
    "stock-quotes.bids_min_1h",
    "stock-quotes.bids_max_1h",
    "stocks.*",
]

vector = fstore.FeatureVector("stocks-vec", features, description="stocks demo feature vector")
vector.save()
resp = fstore.get_offline_features(vector, entity_rows=trades, entity_timestamp_column="time")
resp.to_dataframe()
price quantity multi total_ask bids_min_1h bids_max_1h name exchange
0 51.95 75 155.97 155.94 51.95 51.99 Microsoft Corporation NASDAQ
1 51.95 155 155.97 155.94 51.95 51.99 Microsoft Corporation NASDAQ
2 720.77 100 2161.50 2162.74 720.50 720.50 Alphabet Inc NASDAQ
3 720.92 100 2161.50 2162.74 720.50 720.50 Alphabet Inc NASDAQ
4 98.00 100 293.97 98.01 97.99 97.99 Apple Inc NASDAQ

Initialize an online feature service and use it for real-time inference

service = fstore.get_online_feature_service("stocks-vec")

Request feature vector statistics, can be used for imputing or validation

service.vector.get_stats_table()
count mean min max std hist unique top freq
multi 8.0 925.27875 155.85 2161.50 1024.751408 [[4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... NaN NaN NaN
total_ask 8.0 617.91875 51.96 2162.74 784.877980 [[4, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0,... NaN NaN NaN
bids_min_1h 8.0 308.41125 51.95 720.50 341.596673 [[4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... NaN NaN NaN
bids_max_1h 8.0 308.42625 51.95 720.50 341.583803 [[4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... NaN NaN NaN
name 3.0 NaN NaN NaN NaN NaN 3.0 Alphabet Inc 1.0
exchange 3.0 NaN NaN NaN NaN NaN 1.0 NASDAQ 3.0

Real-time feature vector request

service.get([{"ticker": "GOOG"}, {"ticker": "MSFT"}])
[{'asks5_sum_5h': 2162.74,
  'bids_min_1h': 720.5,
  'bids_max_1h': 720.5,
  'multi': 2161.5,
  'name': 'Alphabet Inc',
  'exchange': 'NASDAQ',
  'total_ask': None},
 {'asks5_sum_5h': 207.97,
  'bids_min_1h': 51.95,
  'bids_max_1h': 52.01,
  'multi': 156.03,
  'name': 'Microsoft Corporation',
  'exchange': 'NASDAQ',
  'total_ask': None}]
service.get([{"ticker": "AAPL"}])
[{'asks5_sum_5h': 98.01,
  'bids_min_1h': 97.99,
  'bids_max_1h': 97.99,
  'multi': 293.97,
  'name': 'Apple Inc',
  'exchange': 'NASDAQ',
  'total_ask': None}]
service.close()