flow alerts multiple tickers
import os
import csv
import requests
import polars as pl
from pathlib import Path
from datetime import datetime
from lets_plot import *
LetsPlot.setup_html()
uw_token = os.environ['UW_TOKEN']
headers = {'Accept': 'application/json, text/plain', 'Authorization': uw_token}
pl.Config.set_tbl_cols(40)
pl.Config.set_fmt_str_lengths(40)
/home/danwagnerco/.cache/pypoetry/virtualenvs/dans-magic-house-uvW-KuUb-py3.12/lib/python3.12/site-packages/lets_plot/plot/annotation.py:150: SyntaxWarning: invalid escape sequence '\^' """ /home/danwagnerco/.cache/pypoetry/virtualenvs/dans-magic-house-uvW-KuUb-py3.12/lib/python3.12/site-packages/lets_plot/plot/tooltip.py:226: SyntaxWarning: invalid escape sequence '\^' """
polars.config.Config
Get recent Flow Alert-type trades for single-name equities
- Data from option-trades/flow alerts endpoint: https://api.unusualwhales.com/docs#/operations/PublicApi.OptionTradeController.flow_alerts
-
We use a
params
dictionary to send some additional criteria to the endpoint: -
issue_types[]
=['Common Stock', 'ADR']
to skip ETFs and indexes -
min_dte
= 1, which means we will always skip 0dte trades -
min_premium
= 200000, which means only trades involving $200K or more will be returned -
min_volume_oi_ratio
= 1.0, which helps us narrow down the universe to potentially opening trades -
rule_name[]
=['RepeatedHits', 'RepeatedHitsAscendingFill', 'RepeatedHitsDescendingFill']
to focus specifically on "urgent" multi-exchange screen trades
We execute the API call in the next cell:
"""
API documentation:
https://api.unusualwhales.com/docs#/operations/PublicApi.OptionTradeController.flow_alerts
"""
url = 'https://api.unusualwhales.com/api/option-trades/flow-alerts'
params = {
'issue_types[]': ['Common Stock', 'ADR'],
'min_dte': 1,
'min_premium': 200000,
'min_volume_oi_ratio': 1.0,
'rule_name[]': ['RepeatedHits', 'RepeatedHitsAscendingFill', 'RepeatedHitsDescendingFill']
}
r = requests.get(url, headers=headers, params=params)
Use a DataFrame package (like polars
) to process
the response
-
First step is to ingest the
json
response into apolars
DataFrame - Then we will convert some columns that are expressed as strings into floats
Let's have at it:
raw_df = pl.DataFrame(r.json()['data'])
clean_df = (
raw_df
.with_columns(
[
pl.col('price').cast(pl.Float64),
pl.col('total_ask_side_prem').cast(pl.Float64),
pl.col('total_bid_side_prem').cast(pl.Float64),
pl.col('total_premium').cast(pl.Float64),
pl.col('underlying_price').cast(pl.Float64),
pl.col('volume_oi_ratio').cast(pl.Float64),
]
)
)
clean_df
alert_rule | all_opening_trades | created_at | end_time | expiry | expiry_count | has_floor | has_multileg | has_singleleg | has_sweep | id | open_interest | option_chain | price | rule_id | sector | start_time | strike | ticker | total_ask_side_prem | total_bid_side_prem | total_premium | total_size | trade_count | type | underlying_price | volume | volume_oi_ratio |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
str | bool | str | i64 | str | i64 | bool | bool | bool | bool | str | i64 | str | f64 | str | str | i64 | str | str | f64 | f64 | f64 | i64 | i64 | str | f64 | i64 | f64 |
"RepeatedHitsAscendingFill" | false | "2024-11-06T21:00:24.359921Z" | 1730926798701 | "2024-11-15" | 1 | false | false | true | false | "96d5b321-c096-4897-84f4-e6243481d2e5" | 10513 | "TSM241115C00200000" | 2.59 | "a0979b52-28e4-4585-8f22-881faad2dd8e" | "Technology" | 1730926798301 | "200" | "TSM" | 264870.0 | 271996.0 | 536866.0 | 2100 | 37 | "call" | 193.3962 | 18920 | 1.799677 |
"RepeatedHitsDescendingFill" | false | "2024-11-06T21:00:24.359921Z" | 1730926798163 | "2024-11-15" | 1 | false | false | true | false | "f06b0f92-d20e-4a1e-a3b3-0b755fcbea75" | 10513 | "TSM241115C00200000" | 2.52 | "5ce5ec11-087c-4c00-b164-08106b015856" | "Technology" | 1730926797890 | "200" | "TSM" | 358977.0 | 17262.0 | 385215.0 | 1531 | 109 | "call" | 193.41 | 16820 | 1.599924 |
"RepeatedHitsAscendingFill" | false | "2024-11-06T20:59:52.879808Z" | 1730926786160 | "2024-11-15" | 1 | false | false | true | false | "fc2a519b-81d9-4d3d-b42c-7a1c788749f8" | 10513 | "TSM241115C00200000" | 2.5 | "a0979b52-28e4-4585-8f22-881faad2dd8e" | "Technology" | 1730926786128 | "200" | "TSM" | 425025.0 | 7641.0 | 434402.0 | 1746 | 81 | "call" | 193.61 | 15209 | 1.446685 |
"RepeatedHitsAscendingFill" | false | "2024-11-06T20:58:40.820468Z" | 1730926712832 | "2025-03-21" | 1 | false | false | true | false | "7f310b51-df89-4838-9371-840a6f5d4ae4" | 424 | "DELL250321C00140000" | 16.8 | "a0979b52-28e4-4585-8f22-881faad2dd8e" | "Technology" | 1730926712826 | "140" | "DELL" | 614876.0 | 0.0 | 614876.0 | 366 | 54 | "call" | 138.28 | 430 | 1.014151 |
"RepeatedHits" | false | "2024-11-06T20:58:35.586376Z" | 1730926708124 | "2024-11-08" | 1 | false | false | true | false | "ec27caaf-6f09-491e-a142-1ca5484bbd59" | 474 | "ARM241108C00146000" | 7.7 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Technology" | 1730926708117 | "146" | "ARM" | 46200.0 | 192500.0 | 238700.0 | 310 | 12 | "call" | 144.9 | 1026 | 2.164557 |
… | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … |
"RepeatedHits" | false | "2024-11-06T16:11:17.563654Z" | 1730909470325 | "2024-11-15" | 1 | false | false | true | true | "6bb43063-bbae-4c0e-ba80-86d0634125ae" | 29596 | "TSLA241115C00300000" | 5.3 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Consumer Cyclical" | 1730909470314 | "300" | "TSLA" | 0.0 | 530000.0 | 530000.0 | 1000 | 7 | "call" | 284.98 | 54470 | 1.840451 |
"RepeatedHits" | false | "2024-11-06T16:11:01.937594Z" | 1730909455013 | "2024-11-15" | 1 | false | false | true | true | "8ee9b95b-e293-428d-81b8-00c12e2ce300" | 29596 | "TSLA241115C00300000" | 5.25 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Consumer Cyclical" | 1730909455009 | "300" | "TSLA" | 0.0 | 262500.0 | 262500.0 | 500 | 15 | "call" | 284.88 | 53395 | 1.804129 |
"RepeatedHitsDescendingFill" | false | "2024-11-06T16:10:27.666171Z" | 1730909420942 | "2024-11-15" | 1 | false | false | true | true | "c27e0b31-4f97-4f64-9673-64819569b51e" | 29596 | "TSLA241115C00300000" | 5.15 | "5ce5ec11-087c-4c00-b164-08106b015856" | "Consumer Cyclical" | 1730909420917 | "300" | "TSLA" | 228138.0 | 0.0 | 228138.0 | 443 | 42 | "call" | 284.68 | 52464 | 1.772672 |
"RepeatedHitsAscendingFill" | false | "2024-11-06T16:05:53.721312Z" | 1730909144715 | "2024-11-15" | 1 | false | false | true | false | "844f3d6d-c31d-4a27-8e68-332c1f7d3421" | 29596 | "TSLA241115C00300000" | 4.85 | "a0979b52-28e4-4585-8f22-881faad2dd8e" | "Consumer Cyclical" | 1730909144381 | "300" | "TSLA" | 722123.0 | 485.0 | 723088.0 | 1501 | 122 | "call" | 283.87 | 51040 | 1.724557 |
"RepeatedHits" | false | "2024-11-06T16:02:46.942791Z" | 1730908961380 | "2024-11-15" | 1 | false | false | true | false | "43ca87f4-5b60-46bc-bda1-ba1f578ef205" | 492 | "TSLA241115P00285000" | 11.2 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Consumer Cyclical" | 1730908961351 | "285" | "TSLA" | 269920.0 | 0.0 | 269920.0 | 241 | 5 | "put" | 283.0 | 7687 | 15.623984 |
Use our knowledge of total_size
vs.
open_interest
for more filtering
- We can be a LOT more certain that a trade was an opener if the size of the trade itself is greater than the open interest on that contract
- So with that in mind, let's filter out trades where the size of the trade is less than the open interest
Filtering a DataFrame in polars
is pretty easy so
let's knock that out next:
opener_df = (
clean_df
.filter(
(
pl.col('total_size') > pl.col('open_interest')
)
)
)
opener_df
alert_rule | all_opening_trades | created_at | end_time | expiry | expiry_count | has_floor | has_multileg | has_singleleg | has_sweep | id | open_interest | option_chain | price | rule_id | sector | start_time | strike | ticker | total_ask_side_prem | total_bid_side_prem | total_premium | total_size | trade_count | type | underlying_price | volume | volume_oi_ratio |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
str | bool | str | i64 | str | i64 | bool | bool | bool | bool | str | i64 | str | f64 | str | str | i64 | str | str | f64 | f64 | f64 | i64 | i64 | str | f64 | i64 | f64 |
"RepeatedHits" | false | "2024-11-06T20:56:09.194335Z" | 1730926563559 | "2025-01-17" | 1 | false | false | true | true | "d60bc445-8a2f-4ffd-a0cc-5afe0dfd2e92" | 873 | "NVO250117P00095000" | 2.42 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Healthcare" | 1730926563555 | "95" | "NVO" | 241516.0 | 0.0 | 241516.0 | 998 | 40 | "put" | 105.3199 | 1137 | 1.302405 |
"RepeatedHits" | false | "2024-11-06T20:53:11.204172Z" | 1730926384223 | "2025-03-21" | 1 | false | false | true | true | "76468e20-6c83-4c47-8325-fd517beb2741" | 62 | "GS250321C00660000" | 15.95 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Financial Services" | 1730926384212 | "660" | "GS" | 234462.0 | 0.0 | 234462.0 | 147 | 41 | "call" | 597.37 | 1032 | 16.645161 |
"RepeatedHitsAscendingFill" | false | "2024-11-06T20:47:52.731549Z" | 1730926066898 | "2024-11-08" | 1 | false | false | true | true | "a6ffdd74-6baa-4a5a-958b-7168adcbec1c" | 2245 | "COIN241108C00300000" | 0.74 | "a0979b52-28e4-4585-8f22-881faad2dd8e" | "Technology" | 1730926066169 | "300" | "COIN" | 73080.0 | 128711.0 | 219341.0 | 3008 | 161 | "call" | 252.3775 | 8760 | 3.902004 |
"RepeatedHitsAscendingFill" | false | "2024-11-06T20:45:06.893254Z" | 1730925901345 | "2025-08-15" | 1 | false | false | true | false | "0e712a35-1243-4611-887b-e791cd34c0e2" | 316 | "TSLA250815P00220000" | 19.0 | "a0979b52-28e4-4585-8f22-881faad2dd8e" | "Consumer Cyclical" | 1730925901263 | "220" | "TSLA" | 146300.0 | 659346.0 | 805646.0 | 424 | 18 | "put" | 288.79 | 611 | 1.933544 |
"RepeatedHitsDescendingFill" | false | "2024-11-06T20:40:36.898760Z" | 1730925631939 | "2027-01-15" | 1 | false | false | true | false | "f16f636d-a714-4e09-a66b-6b4bd4e30692" | 1 | "COIN270115P00260000" | 93.55 | "5ce5ec11-087c-4c00-b164-08106b015856" | "Technology" | 1730925631905 | "260" | "COIN" | 467742.0 | 0.0 | 467742.0 | 50 | 13 | "put" | 253.36 | 59 | 59.0 |
… | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … |
"RepeatedHitsDescendingFill" | false | "2024-11-06T16:23:39.243295Z" | 1730910212644 | "2027-01-15" | 1 | false | false | true | false | "89f90634-b5be-47be-8ec9-28a4756f6822" | 1 | "AXP270115C00370000" | 27.55 | "5ce5ec11-087c-4c00-b164-08106b015856" | "Financial Services" | 1730910212643 | "370" | "AXP" | 217643.0 | 2750.0 | 220393.0 | 80 | 21 | "call" | 291.06 | 97 | 97.0 |
"RepeatedHits" | false | "2024-11-06T16:22:12.891265Z" | 1730910126927 | "2024-11-08" | 1 | false | false | true | false | "a529583c-99ca-4261-8e7f-b177312b471b" | 2799 | "LYFT241108P00013500" | 0.77 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Technology" | 1730910126926 | "13.5" | "LYFT" | 0.0 | 326634.0 | 335258.0 | 4354 | 12 | "put" | 14.115 | 14935 | 5.335834 |
"RepeatedHits" | false | "2024-11-06T16:14:34.117465Z" | 1730909660739 | "2024-11-29" | 1 | false | false | true | false | "6487a13a-8b11-427f-bac9-4af77f8da0c4" | 10 | "HIMS241129P00022500" | 1.5 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Consumer Defensive" | 1730909660656 | "22.5" | "HIMS" | 235200.0 | 2250.0 | 244650.0 | 1631 | 15 | "put" | 23.52 | 8158 | 815.8 |
"RepeatedHits" | false | "2024-11-06T16:13:32.029822Z" | 1730909604489 | "2025-02-21" | 1 | false | false | true | false | "64c56012-8832-4828-8d0d-2c4f02c1ceaa" | 58 | "VKTX250221P00062500" | 9.5 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Healthcare" | 1730909604487 | "62.5" | "VKTX" | 0.0 | 240350.0 | 240350.0 | 253 | 12 | "put" | 64.535 | 266 | 4.586207 |
"RepeatedHits" | false | "2024-11-06T16:11:20.569713Z" | 1730909474810 | "2024-11-29" | 1 | false | false | true | false | "9be1d040-84a3-444f-9c3e-0868e052a67b" | 10 | "HIMS241129P00022500" | 1.5 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Consumer Defensive" | 1730909474664 | "22.5" | "HIMS" | 220950.0 | 1050.0 | 228150.0 | 1521 | 41 | "put" | 23.44 | 6525 | 652.5 |
Can we add some informative and convenient calculations for display?
- Execution time (eastern time zone)
- % Bid and % Ask
- Bullish, Bearish, or Mixed (we'll use 80% as our side threshold)
- Days To Expiration
- Strike and Type Combined
Lots of column manipulation in the polars
DataFrame
in the next cell, but hopefully the "clustering" of these tasks
makes it relatively easy to see what is happening each step of
the way:
display_df = (
opener_df
.with_columns(
pl.col('created_at').str.strptime(pl.Datetime, '%Y-%m-%dT%H:%M:%S%.fZ').alias('created_at_datetime')
)
.with_columns(
pl.col('created_at_datetime').dt.convert_time_zone('America/New_York').alias('created_at_datetime_eastern')
)
.with_columns(
pl.col('created_at_datetime_eastern').dt.strftime('%Y-%m-%d %I:%M:%S %p').alias('created_at_east_str')
)
.with_columns(
[
(pl.col('total_ask_side_prem') / pl.col('total_premium')).alias('pct_ask'),
(pl.col('total_bid_side_prem') / pl.col('total_premium')).alias('pct_bid')
]
)
.with_columns(
pl.when(pl.col('pct_ask') > 0.80).then(pl.lit('ask'))
.when(pl.col('pct_bid') > 0.80).then(pl.lit('bid'))
.otherwise(pl.lit('mixed')).alias('side')
)
.with_columns(
(
((pl.col('pct_ask').round(2) * 100).cast(pl.Utf8)) +
'% Ask / ' +
((pl.col('pct_bid').round(2) * 100).cast(pl.Utf8)) +
'% Bid'
).str.replace_all('.0%', '%').alias('pct_ask_bid_str')
)
.with_columns(
pl.when((pl.col('side') == 'ask') & (pl.col('type') == 'call')).then(pl.lit('bullish'))
.when((pl.col('side') == 'ask') & (pl.col('type') == 'put')).then(pl.lit('bearish'))
.when((pl.col('side') == 'bid') & (pl.col('type') == 'call')).then(pl.lit('bearish'))
.when((pl.col('side') == 'bid') & (pl.col('type') == 'put')).then(pl.lit('bullish'))
.otherwise(pl.lit('mixed')).alias('direction')
)
.with_columns(
pl.col('expiry').str.strptime(pl.Date, '%Y-%m-%d').alias('expiry_date')
)
.with_columns(
(pl.col('expiry_date') - pl.lit(datetime.today().date())).alias('dte')
)
.with_columns(
(pl.col('dte').dt.total_milliseconds() / 86_400_000).alias('dte_days')
)
.with_columns(
pl.col('dte_days').cast(pl.Int64).alias('dte_days_int')
)
.with_columns(
(
pl.when(pl.col('type') == 'call')
.then(pl.col('strike') + 'C')
.otherwise(pl.col('strike') + 'P')
).alias('strike_type')
)
.with_columns(
(
pl.col('ticker') + ' ' +
pl.col('strike_type') + ' ' +
(pl.col('expiry_date').dt.strftime('%m/%d/%Y')).alias('expiry_date_str')
).alias('contract_look_up_format')
)
)
display_df
alert_rule | all_opening_trades | created_at | end_time | expiry | expiry_count | has_floor | has_multileg | has_singleleg | has_sweep | id | open_interest | option_chain | price | rule_id | sector | start_time | strike | ticker | total_ask_side_prem | … | total_size | trade_count | type | underlying_price | volume | volume_oi_ratio | created_at_datetime | created_at_datetime_eastern | created_at_east_str | pct_ask | pct_bid | side | pct_ask_bid_str | direction | expiry_date | dte | dte_days | dte_days_int | strike_type | contract_look_up_format |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
str | bool | str | i64 | str | i64 | bool | bool | bool | bool | str | i64 | str | f64 | str | str | i64 | str | str | f64 | … | i64 | i64 | str | f64 | i64 | f64 | datetime[ns] | datetime[ns, America/New_York] | str | f64 | f64 | str | str | str | date | duration[ms] | f64 | i64 | str | str |
"RepeatedHits" | false | "2024-11-06T20:56:09.194335Z" | 1730926563559 | "2025-01-17" | 1 | false | false | true | true | "d60bc445-8a2f-4ffd-a0cc-5afe0dfd2e92" | 873 | "NVO250117P00095000" | 2.42 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Healthcare" | 1730926563555 | "95" | "NVO" | 241516.0 | … | 998 | 40 | "put" | 105.3199 | 1137 | 1.302405 | 2024-11-06 20:56:09.194335 | 2024-11-06 15:56:09.194335 EST | "2024-11-06 03:56:09 PM" | 1.0 | 0.0 | "ask" | "100% Ask / 0% Bid" | "bearish" | 2025-01-17 | 72d | 72.0 | 72 | "95P" | "NVO 95P 01/17/2025" |
"RepeatedHits" | false | "2024-11-06T20:53:11.204172Z" | 1730926384223 | "2025-03-21" | 1 | false | false | true | true | "76468e20-6c83-4c47-8325-fd517beb2741" | 62 | "GS250321C00660000" | 15.95 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Financial Services" | 1730926384212 | "660" | "GS" | 234462.0 | … | 147 | 41 | "call" | 597.37 | 1032 | 16.645161 | 2024-11-06 20:53:11.204172 | 2024-11-06 15:53:11.204172 EST | "2024-11-06 03:53:11 PM" | 1.0 | 0.0 | "ask" | "100% Ask / 0% Bid" | "bullish" | 2025-03-21 | 135d | 135.0 | 135 | "660C" | "GS 660C 03/21/2025" |
"RepeatedHitsAscendingFill" | false | "2024-11-06T20:47:52.731549Z" | 1730926066898 | "2024-11-08" | 1 | false | false | true | true | "a6ffdd74-6baa-4a5a-958b-7168adcbec1c" | 2245 | "COIN241108C00300000" | 0.74 | "a0979b52-28e4-4585-8f22-881faad2dd8e" | "Technology" | 1730926066169 | "300" | "COIN" | 73080.0 | … | 3008 | 161 | "call" | 252.3775 | 8760 | 3.902004 | 2024-11-06 20:47:52.731549 | 2024-11-06 15:47:52.731549 EST | "2024-11-06 03:47:52 PM" | 0.33318 | 0.586808 | "mixed" | "33% Ask / 59% Bid" | "mixed" | 2024-11-08 | 2d | 2.0 | 2 | "300C" | "COIN 300C 11/08/2024" |
"RepeatedHitsAscendingFill" | false | "2024-11-06T20:45:06.893254Z" | 1730925901345 | "2025-08-15" | 1 | false | false | true | false | "0e712a35-1243-4611-887b-e791cd34c0e2" | 316 | "TSLA250815P00220000" | 19.0 | "a0979b52-28e4-4585-8f22-881faad2dd8e" | "Consumer Cyclical" | 1730925901263 | "220" | "TSLA" | 146300.0 | … | 424 | 18 | "put" | 288.79 | 611 | 1.933544 | 2024-11-06 20:45:06.893254 | 2024-11-06 15:45:06.893254 EST | "2024-11-06 03:45:06 PM" | 0.181593 | 0.818407 | "bid" | "18% Ask / 82% Bid" | "bullish" | 2025-08-15 | 282d | 282.0 | 282 | "220P" | "TSLA 220P 08/15/2025" |
"RepeatedHitsDescendingFill" | false | "2024-11-06T20:40:36.898760Z" | 1730925631939 | "2027-01-15" | 1 | false | false | true | false | "f16f636d-a714-4e09-a66b-6b4bd4e30692" | 1 | "COIN270115P00260000" | 93.55 | "5ce5ec11-087c-4c00-b164-08106b015856" | "Technology" | 1730925631905 | "260" | "COIN" | 467742.0 | … | 50 | 13 | "put" | 253.36 | 59 | 59.0 | 2024-11-06 20:40:36.898760 | 2024-11-06 15:40:36.898760 EST | "2024-11-06 03:40:36 PM" | 1.0 | 0.0 | "ask" | "100% Ask / 0% Bid" | "bearish" | 2027-01-15 | 800d | 800.0 | 800 | "260P" | "COIN 260P 01/15/2027" |
… | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … |
"RepeatedHitsDescendingFill" | false | "2024-11-06T16:23:39.243295Z" | 1730910212644 | "2027-01-15" | 1 | false | false | true | false | "89f90634-b5be-47be-8ec9-28a4756f6822" | 1 | "AXP270115C00370000" | 27.55 | "5ce5ec11-087c-4c00-b164-08106b015856" | "Financial Services" | 1730910212643 | "370" | "AXP" | 217643.0 | … | 80 | 21 | "call" | 291.06 | 97 | 97.0 | 2024-11-06 16:23:39.243295 | 2024-11-06 11:23:39.243295 EST | "2024-11-06 11:23:39 AM" | 0.987522 | 0.012478 | "ask" | "99% Ask / 1% Bid" | "bullish" | 2027-01-15 | 800d | 800.0 | 800 | "370C" | "AXP 370C 01/15/2027" |
"RepeatedHits" | false | "2024-11-06T16:22:12.891265Z" | 1730910126927 | "2024-11-08" | 1 | false | false | true | false | "a529583c-99ca-4261-8e7f-b177312b471b" | 2799 | "LYFT241108P00013500" | 0.77 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Technology" | 1730910126926 | "13.5" | "LYFT" | 0.0 | … | 4354 | 12 | "put" | 14.115 | 14935 | 5.335834 | 2024-11-06 16:22:12.891265 | 2024-11-06 11:22:12.891265 EST | "2024-11-06 11:22:12 AM" | 0.0 | 0.974277 | "bid" | "0% Ask / 97% Bid" | "bullish" | 2024-11-08 | 2d | 2.0 | 2 | "13.5P" | "LYFT 13.5P 11/08/2024" |
"RepeatedHits" | false | "2024-11-06T16:14:34.117465Z" | 1730909660739 | "2024-11-29" | 1 | false | false | true | false | "6487a13a-8b11-427f-bac9-4af77f8da0c4" | 10 | "HIMS241129P00022500" | 1.5 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Consumer Defensive" | 1730909660656 | "22.5" | "HIMS" | 235200.0 | … | 1631 | 15 | "put" | 23.52 | 8158 | 815.8 | 2024-11-06 16:14:34.117465 | 2024-11-06 11:14:34.117465 EST | "2024-11-06 11:14:34 AM" | 0.961373 | 0.009197 | "ask" | "96% Ask / 1% Bid" | "bearish" | 2024-11-29 | 23d | 23.0 | 23 | "22.5P" | "HIMS 22.5P 11/29/2024" |
"RepeatedHits" | false | "2024-11-06T16:13:32.029822Z" | 1730909604489 | "2025-02-21" | 1 | false | false | true | false | "64c56012-8832-4828-8d0d-2c4f02c1ceaa" | 58 | "VKTX250221P00062500" | 9.5 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Healthcare" | 1730909604487 | "62.5" | "VKTX" | 0.0 | … | 253 | 12 | "put" | 64.535 | 266 | 4.586207 | 2024-11-06 16:13:32.029822 | 2024-11-06 11:13:32.029822 EST | "2024-11-06 11:13:32 AM" | 0.0 | 1.0 | "bid" | "0% Ask / 100% Bid" | "bullish" | 2025-02-21 | 107d | 107.0 | 107 | "62.5P" | "VKTX 62.5P 02/21/2025" |
"RepeatedHits" | false | "2024-11-06T16:11:20.569713Z" | 1730909474810 | "2024-11-29" | 1 | false | false | true | false | "9be1d040-84a3-444f-9c3e-0868e052a67b" | 10 | "HIMS241129P00022500" | 1.5 | "e6b9f0b6-fcd9-44fe-9d1c-f53521c152c3" | "Consumer Defensive" | 1730909474664 | "22.5" | "HIMS" | 220950.0 | … | 1521 | 41 | "put" | 23.44 | 6525 | 652.5 | 2024-11-06 16:11:20.569713 | 2024-11-06 11:11:20.569713 EST | "2024-11-06 11:11:20 AM" | 0.968442 | 0.004602 | "ask" | "97% Ask / 0% Bid" | "bearish" | 2024-11-29 | 23d | 23.0 | 23 | "22.5P" | "HIMS 22.5P 11/29/2024" |
Select specific columns for display to the end user
- We've got all the data a trader might want to see at-a-glance, let's cut down this polars DataFrame to fewer columns so it's easier to read
- Then let's export the DataFrame to a list of lists for easy display
Final manipulation before we are finished here! Let's go:
final_df = (
display_df
.select(
[
'created_at_east_str',
'contract_look_up_format',
'total_size',
'price',
'total_premium',
'pct_ask_bid_str',
'direction',
'underlying_price',
'dte_days_int'
]
)
)
final_df
created_at_east_str | contract_look_up_format | total_size | price | total_premium | pct_ask_bid_str | direction | underlying_price | dte_days_int |
---|---|---|---|---|---|---|---|---|
str | str | i64 | f64 | f64 | str | str | f64 | i64 |
"2024-11-06 03:56:09 PM" | "NVO 95P 01/17/2025" | 998 | 2.42 | 241516.0 | "100% Ask / 0% Bid" | "bearish" | 105.3199 | 72 |
"2024-11-06 03:53:11 PM" | "GS 660C 03/21/2025" | 147 | 15.95 | 234462.0 | "100% Ask / 0% Bid" | "bullish" | 597.37 | 135 |
"2024-11-06 03:47:52 PM" | "COIN 300C 11/08/2024" | 3008 | 0.74 | 219341.0 | "33% Ask / 59% Bid" | "mixed" | 252.3775 | 2 |
"2024-11-06 03:45:06 PM" | "TSLA 220P 08/15/2025" | 424 | 19.0 | 805646.0 | "18% Ask / 82% Bid" | "bullish" | 288.79 | 282 |
"2024-11-06 03:40:36 PM" | "COIN 260P 01/15/2027" | 50 | 93.55 | 467742.0 | "100% Ask / 0% Bid" | "bearish" | 253.36 | 800 |
… | … | … | … | … | … | … | … | … |
"2024-11-06 11:23:39 AM" | "AXP 370C 01/15/2027" | 80 | 27.55 | 220393.0 | "99% Ask / 1% Bid" | "bullish" | 291.06 | 800 |
"2024-11-06 11:22:12 AM" | "LYFT 13.5P 11/08/2024" | 4354 | 0.77 | 335258.0 | "0% Ask / 97% Bid" | "bullish" | 14.115 | 2 |
"2024-11-06 11:14:34 AM" | "HIMS 22.5P 11/29/2024" | 1631 | 1.5 | 244650.0 | "96% Ask / 1% Bid" | "bearish" | 23.52 | 23 |
"2024-11-06 11:13:32 AM" | "VKTX 62.5P 02/21/2025" | 253 | 9.5 | 240350.0 | "0% Ask / 100% Bid" | "bullish" | 64.535 | 107 |
"2024-11-06 11:11:20 AM" | "HIMS 22.5P 11/29/2024" | 1521 | 1.5 | 228150.0 | "97% Ask / 0% Bid" | "bearish" | 23.44 | 23 |
# Export the results to CSV (for human review if interested lol)
filename = datetime.today().date().strftime('%Y-%m-%d') + '-flow-alert-openers.csv'
output_path = Path('raw_data') / filename
final_df.write_csv(output_path)