Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save danwagnerco/d6a316a01f1280e6f797f1043289960c to your computer and use it in GitHub Desktop.

Select an option

Save danwagnerco/d6a316a01f1280e6f797f1043289960c to your computer and use it in GitHub Desktop.
3-month rallies after Bob Swan, NKE board member, declares insider stock purchases
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "aaaaed95",
"metadata": {},
"source": [
"Unusual Whales API endpoints we will use in this notebook:\n",
"\n",
"**Insider Transactions**\n",
"- Docs: [https://api.unusualwhales.com/docs#/operations/PublicApi.InsiderController.transactions](https://api.unusualwhales.com/docs#/operations/PublicApi.InsiderController.transactions)\n",
"- GET: `https://api.unusualwhales.com/api/insider/transactions`\n",
"- Why: This endpoint delivers transaction-level data from corporate insiders\n",
"\n",
"**Realized Volatility**\n",
"- Docs: [https://api.unusualwhales.com/docs#/operations/PublicApi.TickerController.realized_volatility](https://api.unusualwhales.com/docs#/operations/PublicApi.TickerController.realized_volatility)\n",
"- GET: `https://api.unusualwhales.com/api/stock/{ticker}/volatility/realized`\n",
"- Why: A little \"inside baseball\" here, since we are only going to use end of day \"close\" prices we can use this lean RV endpoint instead of the larger OHLC endpoint"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "65be815c",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" <div id=\"zv6tZ7\"></div>\n",
" <script type=\"text/javascript\" data-lets-plot-script=\"library\">\n",
" if(!window.letsPlotCallQueue) {\n",
" window.letsPlotCallQueue = [];\n",
" }; \n",
" window.letsPlotCall = function(f) {\n",
" window.letsPlotCallQueue.push(f);\n",
" };\n",
" (function() {\n",
" var script = document.createElement(\"script\");\n",
" script.type = \"text/javascript\";\n",
" script.src = \"https://cdn.jsdelivr.net/gh/JetBrains/lets-plot@v4.3.3/js-package/distr/lets-plot.min.js\";\n",
" script.onload = function() {\n",
" window.letsPlotCall = function(f) {f();};\n",
" window.letsPlotCallQueue.forEach(function(f) {f();});\n",
" window.letsPlotCallQueue = [];\n",
" \n",
" };\n",
" script.onerror = function(event) {\n",
" window.letsPlotCall = function(f) {}; // noop\n",
" window.letsPlotCallQueue = [];\n",
" var div = document.createElement(\"div\");\n",
" div.style.color = 'darkred';\n",
" div.textContent = 'Error loading Lets-Plot JS';\n",
" document.getElementById(\"zv6tZ7\").appendChild(div);\n",
" };\n",
" var e = document.getElementById(\"zv6tZ7\");\n",
" e.appendChild(script);\n",
" })()\n",
" </script>\n",
" "
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import os\n",
"import httpx # pip install httpx\n",
"import polars as pl # pip install polars\n",
"import lets_plot as lp # pip install lets-plot\n",
"lp.LetsPlot.setup_html() # Enable lets-plot for use with notebook\n",
"\n",
"UW_TOKEN = os.environ.get(\"UW_TOKEN\") # API token stored in an environment variable\n",
"HEADERS = {\n",
" \"Accept\": \"application/json, text/plain\",\n",
" \"Authorization\": f\"Bearer {UW_TOKEN}\"\n",
"}"
]
},
{
"cell_type": "markdown",
"id": "5529e377",
"metadata": {},
"source": [
"You might have heard that Tim Cook, CEO of Apple and NKE board member, announced an ad hoc purchase of 50,000 shares of NKE this past Tuesday (Dec 23rd, 2025) for $2.95M:\n",
"\n",
"[https://x.com/unusual_whales/status/2003597602982625727?s=20](https://x.com/unusual_whales/status/2003597602982625727?s=20)\n",
"\n",
"What I thought was more interesting, though, was the fact that fellow NKE board member Robert Holmes Swan (known colloquially as \"Bob Swan\") also announced an ad hoc purchase for 8,691 shares totaling $500K.\n",
"\n",
"**Why is Swan's purchase, which is a tiny fraction of Tim Cook's, so interesting?**\n",
"\n",
"Swan has a track record of timely dip buying in NKE stock:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "6f974dcf",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><style>\n",
".dataframe > thead > tr,\n",
".dataframe > tbody > tr {\n",
" text-align: right;\n",
" white-space: pre-wrap;\n",
"}\n",
"</style>\n",
"<small>shape: (5, 31)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>id</th><th>ticker</th><th>amount</th><th>transactions</th><th>price</th><th>sector</th><th>marketcap</th><th>next_earnings_date</th><th>is_s_p_500</th><th>transaction_date</th><th>filing_date</th><th>is_director</th><th>is_officer</th><th>is_ten_percent_owner</th><th>reporter_is_public_company</th><th>stock_price</th><th>security_title</th><th>formtype</th><th>transaction_code</th><th>is_10b5_1</th><th>owner_name</th><th>security_ad_code</th><th>shares_owned_after</th><th>officer_title</th><th>shares_owned_before</th><th>director_indirect</th><th>natureofownership</th><th>date_excercisable</th><th>price_excercisable</th><th>expiration_date</th><th>ids</th></tr><tr><td>str</td><td>str</td><td>i64</td><td>i64</td><td>str</td><td>str</td><td>str</td><td>str</td><td>bool</td><td>str</td><td>str</td><td>bool</td><td>bool</td><td>bool</td><td>bool</td><td>str</td><td>str</td><td>str</td><td>str</td><td>bool</td><td>str</td><td>str</td><td>i64</td><td>str</td><td>i64</td><td>str</td><td>str</td><td>null</td><td>str</td><td>str</td><td>list[str]</td></tr></thead><tbody><tr><td>&quot;d4a833c5-92ae-401d-b0ba-cb0585…</td><td>&quot;NKE&quot;</td><td>8691</td><td>1</td><td>&quot;57.5400&quot;</td><td>&quot;Consumer Cyclical&quot;</td><td>&quot;72464878318&quot;</td><td>&quot;2026-03-19&quot;</td><td>true</td><td>&quot;2025-12-22&quot;</td><td>&quot;2025-12-23&quot;</td><td>true</td><td>false</td><td>false</td><td>false</td><td>&quot;60.93&quot;</td><td>&quot;Class B Common Stock&quot;</td><td>&quot;4&quot;</td><td>&quot;P&quot;</td><td>false</td><td>&quot;SWAN ROBERT HOLMES&quot;</td><td>&quot;NA&quot;</td><td>43293</td><td>null</td><td>34602</td><td>&quot;D&quot;</td><td>null</td><td>null</td><td>null</td><td>null</td><td>[&quot;1fc22d5d-1f1b-450a-92bb-2ff050e8a6ba&quot;]</td></tr><tr><td>&quot;93fd147e-320f-4bb2-84a0-cb9015…</td><td>&quot;NKE&quot;</td><td>50000</td><td>1</td><td>&quot;58.9700&quot;</td><td>&quot;Consumer Cyclical&quot;</td><td>&quot;72464878318&quot;</td><td>&quot;2026-03-19&quot;</td><td>true</td><td>&quot;2025-12-22&quot;</td><td>&quot;2025-12-23&quot;</td><td>true</td><td>false</td><td>false</td><td>false</td><td>&quot;60.93&quot;</td><td>&quot;Class B Common Stock&quot;</td><td>&quot;4&quot;</td><td>&quot;P&quot;</td><td>false</td><td>&quot;COOK TIMOTHY&quot;</td><td>&quot;NA&quot;</td><td>105480</td><td>null</td><td>55480</td><td>&quot;D&quot;</td><td>null</td><td>null</td><td>null</td><td>null</td><td>[&quot;27920e26-5e6b-4690-969b-ffa2a98ec246&quot;]</td></tr><tr><td>&quot;358cf67c-b74d-410b-a654-79f650…</td><td>&quot;NKE&quot;</td><td>36645</td><td>2</td><td>&quot;0.0000&quot;</td><td>&quot;Consumer Cyclical&quot;</td><td>&quot;72464878318&quot;</td><td>&quot;2026-03-19&quot;</td><td>true</td><td>&quot;2025-12-10&quot;</td><td>&quot;2025-12-16&quot;</td><td>false</td><td>true</td><td>false</td><td>false</td><td>&quot;60.93&quot;</td><td>&quot;Class B Common Stock&quot;</td><td>&quot;4&quot;</td><td>&quot;A&quot;</td><td>false</td><td>&quot;ALAGIRISAMY VENKATESH&quot;</td><td>&quot;NA&quot;</td><td>86040</td><td>&quot;EVP: CHIEF OPERATING OFFICER&quot;</td><td>49395</td><td>&quot;D&quot;</td><td>null</td><td>null</td><td>null</td><td>null</td><td>[&quot;c5a0ba7e-9c23-424d-87e4-491cc16c5858&quot;, &quot;1bceeaa4-a9ab-4b33-96f5-77242482e969&quot;]</td></tr><tr><td>&quot;70683e11-4ff9-4bc4-a666-c7dd0d…</td><td>&quot;NKE&quot;</td><td>17615</td><td>1</td><td>&quot;65.7900&quot;</td><td>&quot;Consumer Cyclical&quot;</td><td>&quot;72464878318&quot;</td><td>&quot;2026-03-19&quot;</td><td>true</td><td>&quot;2025-12-10&quot;</td><td>&quot;2025-12-16&quot;</td><td>false</td><td>true</td><td>false</td><td>false</td><td>&quot;60.93&quot;</td><td>&quot;Non-Qualified Stock Option (Ri…</td><td>&quot;4&quot;</td><td>&quot;A&quot;</td><td>false</td><td>&quot;ALAGIRISAMY VENKATESH&quot;</td><td>&quot;DA&quot;</td><td>17615</td><td>&quot;EVP: CHIEF OPERATING OFFICER&quot;</td><td>0</td><td>&quot;D&quot;</td><td>null</td><td>null</td><td>&quot;65.79&quot;</td><td>&quot;2035-12-10&quot;</td><td>[&quot;50240147-a223-426f-9283-6433e69368c6&quot;]</td></tr><tr><td>&quot;f2ee1726-3a42-4622-a947-00216c…</td><td>&quot;NKE&quot;</td><td>31216</td><td>1</td><td>&quot;0.0000&quot;</td><td>&quot;Consumer Cyclical&quot;</td><td>&quot;72464878318&quot;</td><td>&quot;2026-03-19&quot;</td><td>true</td><td>&quot;2025-12-10&quot;</td><td>&quot;2025-12-12&quot;</td><td>false</td><td>true</td><td>false</td><td>false</td><td>&quot;60.93&quot;</td><td>&quot;Class B Common Stock&quot;</td><td>&quot;4&quot;</td><td>&quot;A&quot;</td><td>false</td><td>&quot;FRIEND MATTHEW&quot;</td><td>&quot;NA&quot;</td><td>85530</td><td>&quot;EVP: CFO&quot;</td><td>54314</td><td>&quot;D&quot;</td><td>null</td><td>null</td><td>null</td><td>null</td><td>[&quot;8e733519-6e85-4d16-9db5-1bd17aa1a568&quot;]</td></tr></tbody></table></div>"
],
"text/plain": [
"shape: (5, 31)\n",
"┌────────────┬────────┬────────┬────────────┬───┬────────────┬────────────┬────────────┬───────────┐\n",
"│ id ┆ ticker ┆ amount ┆ transactio ┆ … ┆ date_excer ┆ price_exce ┆ expiration ┆ ids │\n",
"│ --- ┆ --- ┆ --- ┆ ns ┆ ┆ cisable ┆ rcisable ┆ _date ┆ --- │\n",
"│ str ┆ str ┆ i64 ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ list[str] │\n",
"│ ┆ ┆ ┆ i64 ┆ ┆ null ┆ str ┆ str ┆ │\n",
"╞════════════╪════════╪════════╪════════════╪═══╪════════════╪════════════╪════════════╪═══════════╡\n",
"│ d4a833c5-9 ┆ NKE ┆ 8691 ┆ 1 ┆ … ┆ null ┆ null ┆ null ┆ [\"1fc22d5 │\n",
"│ 2ae-401d-b ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ d-1f1b-45 │\n",
"│ 0ba-cb0585 ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 0a-92bb-2 │\n",
"│ … ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ff0… │\n",
"│ 93fd147e-3 ┆ NKE ┆ 50000 ┆ 1 ┆ … ┆ null ┆ null ┆ null ┆ [\"27920e2 │\n",
"│ 20f-4bb2-8 ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 6-5e6b-46 │\n",
"│ 4a0-cb9015 ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 90-969b-f │\n",
"│ … ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ fa2… │\n",
"│ 358cf67c-b ┆ NKE ┆ 36645 ┆ 2 ┆ … ┆ null ┆ null ┆ null ┆ [\"c5a0ba7 │\n",
"│ 74d-410b-a ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ e-9c23-42 │\n",
"│ 654-79f650 ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 4d-87e4-4 │\n",
"│ … ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 91c… │\n",
"│ 70683e11-4 ┆ NKE ┆ 17615 ┆ 1 ┆ … ┆ null ┆ 65.79 ┆ 2035-12-10 ┆ [\"5024014 │\n",
"│ ff9-4bc4-a ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 7-a223-42 │\n",
"│ 666-c7dd0d ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 6f-9283-6 │\n",
"│ … ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 433… │\n",
"│ f2ee1726-3 ┆ NKE ┆ 31216 ┆ 1 ┆ … ┆ null ┆ null ┆ null ┆ [\"8e73351 │\n",
"│ a42-4622-a ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 9-6e85-4d │\n",
"│ 947-00216c ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 16-9db5-1 │\n",
"│ … ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ bd1… │\n",
"└────────────┴────────┴────────┴────────────┴───┴────────────┴────────────┴────────────┴───────────┘"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# First, let's collect the latest insider transactions in NKE\n",
"ticker = \"NKE\"\n",
"url = \"https://api.unusualwhales.com/api/insider/transactions\"\n",
"params = {\n",
" \"ticker_symbol\": ticker,\n",
" \"limit\": 500,\n",
"}\n",
"rsp = httpx.get(url, headers=HEADERS, params=params)\n",
"if (rsp.status_code != 200) or len(rsp.json().get(\"data\")) == 0:\n",
" print(f\"Error fetching insider transactions for {ticker}: {rsp.status_code}\")\n",
" # exit(1)\n",
"\n",
"nke_insider_df = pl.DataFrame(rsp.json().get(\"data\"))\n",
"nke_insider_df.head()"
]
},
{
"cell_type": "markdown",
"id": "70fad5b6",
"metadata": {},
"source": [
"Let's filter the insider dataframe down to Bob Swan's share purchases (where the \"transaction_code\" field is \"P\") and sales (where the \"transaction_code\" field is \"S\") and prep the columns for an eventual merge with a dataframe of NKE prices over time:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "e7efdaa9",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><style>\n",
".dataframe > thead > tr,\n",
".dataframe > tbody > tr {\n",
" text-align: right;\n",
" white-space: pre-wrap;\n",
"}\n",
"</style>\n",
"<small>shape: (4, 4)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>date</th><th>purchase_price_cents</th><th>amount</th><th>transaction_code</th></tr><tr><td>str</td><td>i32</td><td>i64</td><td>str</td></tr></thead><tbody><tr><td>&quot;2023-10-02&quot;</td><td>9600</td><td>13072</td><td>&quot;P&quot;</td></tr><tr><td>&quot;2024-06-28&quot;</td><td>7700</td><td>2941</td><td>&quot;P&quot;</td></tr><tr><td>&quot;2025-04-04&quot;</td><td>5800</td><td>8600</td><td>&quot;P&quot;</td></tr><tr><td>&quot;2025-12-22&quot;</td><td>5754</td><td>8691</td><td>&quot;P&quot;</td></tr></tbody></table></div>"
],
"text/plain": [
"shape: (4, 4)\n",
"┌────────────┬──────────────────────┬────────┬──────────────────┐\n",
"│ date ┆ purchase_price_cents ┆ amount ┆ transaction_code │\n",
"│ --- ┆ --- ┆ --- ┆ --- │\n",
"│ str ┆ i32 ┆ i64 ┆ str │\n",
"╞════════════╪══════════════════════╪════════╪══════════════════╡\n",
"│ 2023-10-02 ┆ 9600 ┆ 13072 ┆ P │\n",
"│ 2024-06-28 ┆ 7700 ┆ 2941 ┆ P │\n",
"│ 2025-04-04 ┆ 5800 ┆ 8600 ┆ P │\n",
"│ 2025-12-22 ┆ 5754 ┆ 8691 ┆ P │\n",
"└────────────┴──────────────────────┴────────┴──────────────────┘"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bob_swan_df = (\n",
" nke_insider_df\n",
" .filter(\n",
" (pl.col(\"owner_name\") == \"SWAN ROBERT HOLMES\")\n",
" & ((pl.col(\"transaction_code\") == \"P\") | (pl.col(\"transaction_code\") == \"S\"))\n",
" )\n",
" .with_columns(\n",
" purchase_price_cents = (pl.col(\"price\").cast(pl.Float64) * 100).cast(pl.Int32),\n",
" date = pl.col(\"transaction_date\"),\n",
" )\n",
" .select(\"date\", \"purchase_price_cents\", \"amount\", \"transaction_code\")\n",
" .sort(\"date\", descending=False)\n",
")\n",
"bob_swan_df.head()"
]
},
{
"cell_type": "markdown",
"id": "174eafd3",
"metadata": {},
"source": [
"Nice, this concise dataframe is ready to plot on a NKE price graph, which we will create next:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "2201c509",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><style>\n",
".dataframe > thead > tr,\n",
".dataframe > tbody > tr {\n",
" text-align: right;\n",
" white-space: pre-wrap;\n",
"}\n",
"</style>\n",
"<small>shape: (5, 2)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>date</th><th>price_cents</th></tr><tr><td>str</td><td>i32</td></tr></thead><tbody><tr><td>&quot;2023-07-17&quot;</td><td>10871</td></tr><tr><td>&quot;2023-07-18&quot;</td><td>10972</td></tr><tr><td>&quot;2023-07-19&quot;</td><td>10988</td></tr><tr><td>&quot;2023-07-20&quot;</td><td>10753</td></tr><tr><td>&quot;2023-07-21&quot;</td><td>10906</td></tr></tbody></table></div>"
],
"text/plain": [
"shape: (5, 2)\n",
"┌────────────┬─────────────┐\n",
"│ date ┆ price_cents │\n",
"│ --- ┆ --- │\n",
"│ str ┆ i32 │\n",
"╞════════════╪═════════════╡\n",
"│ 2023-07-17 ┆ 10871 │\n",
"│ 2023-07-18 ┆ 10972 │\n",
"│ 2023-07-19 ┆ 10988 │\n",
"│ 2023-07-20 ┆ 10753 │\n",
"│ 2023-07-21 ┆ 10906 │\n",
"└────────────┴─────────────┘"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"url = f\"https://api.unusualwhales.com/api/stock/{ticker}/volatility/realized\"\n",
"params = {\"timeframe\": \"4Y\"}\n",
"rsp = httpx.get(url, headers=HEADERS, params=params)\n",
"raw_price_df = pl.DataFrame(rsp.json()[\"data\"])\n",
"price_df = (\n",
" raw_price_df\n",
" .with_columns(\n",
" price_cents = (pl.col(\"price\").cast(pl.Float64) * 100).cast(pl.Int32),\n",
" )\n",
" .select(\"date\", \"price_cents\")\n",
")\n",
"price_df.head()"
]
},
{
"cell_type": "markdown",
"id": "5c47ee5d",
"metadata": {},
"source": [
"Finally, let's combine these into a single \"combo\" dataframe for plotting:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "601e1ace",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><style>\n",
".dataframe > thead > tr,\n",
".dataframe > tbody > tr {\n",
" text-align: right;\n",
" white-space: pre-wrap;\n",
"}\n",
"</style>\n",
"<small>shape: (5, 7)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>date</th><th>price_cents</th><th>amount</th><th>purchase_price_cents</th><th>transaction_code</th><th>price</th><th>purchase_price</th></tr><tr><td>str</td><td>i32</td><td>i64</td><td>i32</td><td>str</td><td>f64</td><td>f64</td></tr></thead><tbody><tr><td>&quot;2025-12-19&quot;</td><td>5871</td><td>null</td><td>null</td><td>null</td><td>58.71</td><td>null</td></tr><tr><td>&quot;2025-12-22&quot;</td><td>5722</td><td>8691</td><td>5754</td><td>&quot;P&quot;</td><td>57.22</td><td>57.54</td></tr><tr><td>&quot;2025-12-23&quot;</td><td>5734</td><td>null</td><td>null</td><td>null</td><td>57.34</td><td>null</td></tr><tr><td>&quot;2025-12-24&quot;</td><td>6000</td><td>null</td><td>null</td><td>null</td><td>60.0</td><td>null</td></tr><tr><td>&quot;2025-12-26&quot;</td><td>6093</td><td>null</td><td>null</td><td>null</td><td>60.93</td><td>null</td></tr></tbody></table></div>"
],
"text/plain": [
"shape: (5, 7)\n",
"┌────────────┬─────────────┬────────┬──────────────────┬──────────────────┬───────┬────────────────┐\n",
"│ date ┆ price_cents ┆ amount ┆ purchase_price_c ┆ transaction_code ┆ price ┆ purchase_price │\n",
"│ --- ┆ --- ┆ --- ┆ ents ┆ --- ┆ --- ┆ --- │\n",
"│ str ┆ i32 ┆ i64 ┆ --- ┆ str ┆ f64 ┆ f64 │\n",
"│ ┆ ┆ ┆ i32 ┆ ┆ ┆ │\n",
"╞════════════╪═════════════╪════════╪══════════════════╪══════════════════╪═══════╪════════════════╡\n",
"│ 2025-12-19 ┆ 5871 ┆ null ┆ null ┆ null ┆ 58.71 ┆ null │\n",
"│ 2025-12-22 ┆ 5722 ┆ 8691 ┆ 5754 ┆ P ┆ 57.22 ┆ 57.54 │\n",
"│ 2025-12-23 ┆ 5734 ┆ null ┆ null ┆ null ┆ 57.34 ┆ null │\n",
"│ 2025-12-24 ┆ 6000 ┆ null ┆ null ┆ null ┆ 60.0 ┆ null │\n",
"│ 2025-12-26 ┆ 6093 ┆ null ┆ null ┆ null ┆ 60.93 ┆ null │\n",
"└────────────┴─────────────┴────────┴──────────────────┴──────────────────┴───────┴────────────────┘"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"combo_df = (\n",
" price_df\n",
" .join(bob_swan_df, on=\"date\", how=\"left\")\n",
" .select(\"date\", \"price_cents\", \"amount\", \"purchase_price_cents\", \"transaction_code\")\n",
" .with_columns(\n",
" price = (pl.col(\"price_cents\") / 100),\n",
" purchase_price = (pl.col(\"purchase_price_cents\") / 100),\n",
" )\n",
")\n",
"combo_df.tail()"
]
},
{
"cell_type": "markdown",
"id": "d0bf2136",
"metadata": {},
"source": [
"Here's where Bob Swan's NKE purchases have landed over time:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "5ffab7da",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
" <div id=\"z5dOE6\"></div>\n",
" <script type=\"text/javascript\" data-lets-plot-script=\"plot\">\n",
" (function() {\n",
" var plotSpec={\n",
"\"mapping\":{\n",
"},\n",
"\"data_meta\":{\n",
"},\n",
"\"ggtitle\":{\n",
"\"text\":\"NKE Stock Price with Robert Holmes Swan Purchases\"\n",
"},\n",
"\"ggsize\":{\n",
"\"width\":800.0,\n",
"\"height\":500.0\n",
"},\n",
"\"theme\":{\n",
"\"name\":\"none\",\n",
"\"line\":{\n",
"\"color\":\"#f9fbfd\",\n",
"\"size\":3.0,\n",
"\"blank\":false\n",
"},\n",
"\"rect\":{\n",
"\"fill\":\"#161c2d\",\n",
"\"color\":\"#161c2d\",\n",
"\"size\":2.0,\n",
"\"blank\":false\n",
"},\n",
"\"text\":{\n",
"\"color\":\"#f9fbfd\",\n",
"\"size\":10.0,\n",
"\"blank\":false\n",
"},\n",
"\"axis_ontop\":true,\n",
"\"axis_ticks\":{\n",
"\"color\":\"#f9fbfd\",\n",
"\"size\":1.0,\n",
"\"blank\":false\n",
"},\n",
"\"axis_line\":{\n",
"\"color\":\"#f9fbfd\",\n",
"\"size\":3.0,\n",
"\"blank\":false\n",
"},\n",
"\"legend_background\":{\n",
"\"fill\":\"#161c2d\",\n",
"\"color\":\"#f9fbfd\",\n",
"\"size\":2.0,\n",
"\"blank\":false\n",
"},\n",
"\"panel_background\":{\n",
"\"fill\":\"#161c2d\",\n",
"\"blank\":false\n",
"},\n",
"\"panel_grid_major\":{\n",
"\"blank\":true\n",
"},\n",
"\"panel_grid_minor\":{\n",
"\"blank\":true\n",
"},\n",
"\"plot_background\":{\n",
"\"fill\":\"#161c2d\",\n",
"\"blank\":false\n",
"},\n",
"\"plot_title\":{\n",
"\"color\":\"#f9fbfd\",\n",
"\"size\":16.0,\n",
"\"hjust\":0.5,\n",
"\"blank\":false\n",
"},\n",
"\"axis_tooltip\":{\n",
"\"color\":\"#f9fbfd\",\n",
"\"blank\":false\n",
"},\n",
"\"tooltip\":{\n",
"\"fill\":\"#161c2d\",\n",
"\"color\":\"#f9fbfd\",\n",
"\"blank\":false\n",
"},\n",
"\"legend_position\":\"bottom\"\n",
"},\n",
"\"kind\":\"plot\",\n",
"\"scales\":[{\n",
"\"name\":\"Date\",\n",
"\"aesthetic\":\"x\"\n",
"},{\n",
"\"name\":\"Price (USD)\",\n",
"\"aesthetic\":\"y\"\n",
"},{\n",
"\"aesthetic\":\"y\",\n",
"\"position\":\"right\"\n",
"},{\n",
"\"aesthetic\":\"x\",\n",
"\"expand\":[0.05,0.0],\n",
"\"discrete\":true,\n",
"\"reverse\":false\n",
"}],\n",
"\"layers\":[{\n",
"\"geom\":\"line\",\n",
"\"data\":{\n",
"\"date\":[\"2023-07-17\",\"2023-07-18\",\"2023-07-19\",\"2023-07-20\",\"2023-07-21\",\"2023-07-24\",\"2023-07-25\",\"2023-07-26\",\"2023-07-27\",\"2023-07-28\",\"2023-07-31\",\"2023-08-01\",\"2023-08-02\",\"2023-08-03\",\"2023-08-04\",\"2023-08-07\",\"2023-08-08\",\"2023-08-09\",\"2023-08-10\",\"2023-08-11\",\"2023-08-14\",\"2023-08-15\",\"2023-08-16\",\"2023-08-17\",\"2023-08-18\",\"2023-08-21\",\"2023-08-22\",\"2023-08-23\",\"2023-08-24\",\"2023-08-25\",\"2023-08-28\",\"2023-08-29\",\"2023-08-30\",\"2023-08-31\",\"2023-09-01\",\"2023-09-05\",\"2023-09-06\",\"2023-09-07\",\"2023-09-08\",\"2023-09-11\",\"2023-09-12\",\"2023-09-13\",\"2023-09-14\",\"2023-09-15\",\"2023-09-18\",\"2023-09-19\",\"2023-09-20\",\"2023-09-21\",\"2023-09-22\",\"2023-09-25\",\"2023-09-26\",\"2023-09-27\",\"2023-09-28\",\"2023-09-29\",\"2023-10-02\",\"2023-10-03\",\"2023-10-04\",\"2023-10-05\",\"2023-10-06\",\"2023-10-09\",\"2023-10-10\",\"2023-10-11\",\"2023-10-12\",\"2023-10-13\",\"2023-10-16\",\"2023-10-17\",\"2023-10-18\",\"2023-10-19\",\"2023-10-20\",\"2023-10-23\",\"2023-10-24\",\"2023-10-25\",\"2023-10-26\",\"2023-10-27\",\"2023-10-30\",\"2023-10-31\",\"2023-11-01\",\"2023-11-02\",\"2023-11-03\",\"2023-11-06\",\"2023-11-07\",\"2023-11-08\",\"2023-11-09\",\"2023-11-10\",\"2023-11-13\",\"2023-11-14\",\"2023-11-15\",\"2023-11-16\",\"2023-11-17\",\"2023-11-20\",\"2023-11-21\",\"2023-11-22\",\"2023-11-24\",\"2023-11-27\",\"2023-11-28\",\"2023-11-29\",\"2023-11-30\",\"2023-12-01\",\"2023-12-04\",\"2023-12-05\",\"2023-12-06\",\"2023-12-07\",\"2023-12-08\",\"2023-12-11\",\"2023-12-12\",\"2023-12-13\",\"2023-12-14\",\"2023-12-15\",\"2023-12-18\",\"2023-12-19\",\"2023-12-20\",\"2023-12-21\",\"2023-12-22\",\"2023-12-26\",\"2023-12-27\",\"2023-12-28\",\"2023-12-29\",\"2024-01-02\",\"2024-01-03\",\"2024-01-04\",\"2024-01-05\",\"2024-01-08\",\"2024-01-09\",\"2024-01-10\",\"2024-01-11\",\"2024-01-12\",\"2024-01-16\",\"2024-01-17\",\"2024-01-18\",\"2024-01-19\",\"2024-01-22\",\"2024-01-23\",\"2024-01-24\",\"2024-01-25\",\"2024-01-26\",\"2024-01-29\",\"2024-01-30\",\"2024-01-31\",\"2024-02-01\",\"2024-02-02\",\"2024-02-05\",\"2024-02-06\",\"2024-02-07\",\"2024-02-08\",\"2024-02-09\",\"2024-02-12\",\"2024-02-13\",\"2024-02-14\",\"2024-02-15\",\"2024-02-16\",\"2024-02-20\",\"2024-02-21\",\"2024-02-22\",\"2024-02-23\",\"2024-02-26\",\"2024-02-27\",\"2024-02-28\",\"2024-02-29\",\"2024-03-01\",\"2024-03-04\",\"2024-03-05\",\"2024-03-06\",\"2024-03-07\",\"2024-03-08\",\"2024-03-11\",\"2024-03-12\",\"2024-03-13\",\"2024-03-14\",\"2024-03-15\",\"2024-03-18\",\"2024-03-19\",\"2024-03-20\",\"2024-03-21\",\"2024-03-22\",\"2024-03-25\",\"2024-03-26\",\"2024-03-27\",\"2024-03-28\",\"2024-04-01\",\"2024-04-02\",\"2024-04-03\",\"2024-04-04\",\"2024-04-05\",\"2024-04-08\",\"2024-04-09\",\"2024-04-10\",\"2024-04-11\",\"2024-04-12\",\"2024-04-15\",\"2024-04-16\",\"2024-04-17\",\"2024-04-18\",\"2024-04-19\",\"2024-04-22\",\"2024-04-23\",\"2024-04-24\",\"2024-04-25\",\"2024-04-26\",\"2024-04-29\",\"2024-04-30\",\"2024-05-01\",\"2024-05-02\",\"2024-05-03\",\"2024-05-06\",\"2024-05-07\",\"2024-05-08\",\"2024-05-09\",\"2024-05-10\",\"2024-05-13\",\"2024-05-14\",\"2024-05-15\",\"2024-05-16\",\"2024-05-17\",\"2024-05-20\",\"2024-05-21\",\"2024-05-22\",\"2024-05-23\",\"2024-05-24\",\"2024-05-28\",\"2024-05-29\",\"2024-05-30\",\"2024-05-31\",\"2024-06-03\",\"2024-06-04\",\"2024-06-05\",\"2024-06-06\",\"2024-06-07\",\"2024-06-10\",\"2024-06-11\",\"2024-06-12\",\"2024-06-13\",\"2024-06-14\",\"2024-06-17\",\"2024-06-18\",\"2024-06-20\",\"2024-06-21\",\"2024-06-24\",\"2024-06-25\",\"2024-06-26\",\"2024-06-27\",\"2024-06-28\",\"2024-07-01\",\"2024-07-02\",\"2024-07-03\",\"2024-07-05\",\"2024-07-08\",\"2024-07-09\",\"2024-07-10\",\"2024-07-11\",\"2024-07-12\",\"2024-07-15\",\"2024-07-16\",\"2024-07-17\",\"2024-07-18\",\"2024-07-19\",\"2024-07-22\",\"2024-07-23\",\"2024-07-24\",\"2024-07-25\",\"2024-07-26\",\"2024-07-29\",\"2024-07-30\",\"2024-07-31\",\"2024-08-01\",\"2024-08-02\",\"2024-08-05\",\"2024-08-06\",\"2024-08-07\",\"2024-08-08\",\"2024-08-09\",\"2024-08-12\",\"2024-08-13\",\"2024-08-14\",\"2024-08-15\",\"2024-08-16\",\"2024-08-19\",\"2024-08-20\",\"2024-08-21\",\"2024-08-22\",\"2024-08-23\",\"2024-08-26\",\"2024-08-27\",\"2024-08-28\",\"2024-08-29\",\"2024-08-30\",\"2024-09-03\",\"2024-09-04\",\"2024-09-05\",\"2024-09-06\",\"2024-09-09\",\"2024-09-10\",\"2024-09-11\",\"2024-09-12\",\"2024-09-13\",\"2024-09-16\",\"2024-09-17\",\"2024-09-18\",\"2024-09-19\",\"2024-09-20\",\"2024-09-23\",\"2024-09-24\",\"2024-09-25\",\"2024-09-26\",\"2024-09-27\",\"2024-09-30\",\"2024-10-01\",\"2024-10-02\",\"2024-10-03\",\"2024-10-04\",\"2024-10-07\",\"2024-10-08\",\"2024-10-09\",\"2024-10-10\",\"2024-10-11\",\"2024-10-14\",\"2024-10-15\",\"2024-10-16\",\"2024-10-17\",\"2024-10-18\",\"2024-10-21\",\"2024-10-22\",\"2024-10-23\",\"2024-10-24\",\"2024-10-25\",\"2024-10-28\",\"2024-10-29\",\"2024-10-30\",\"2024-10-31\",\"2024-11-01\",\"2024-11-04\",\"2024-11-05\",\"2024-11-06\",\"2024-11-07\",\"2024-11-08\",\"2024-11-11\",\"2024-11-12\",\"2024-11-13\",\"2024-11-14\",\"2024-11-15\",\"2024-11-18\",\"2024-11-19\",\"2024-11-20\",\"2024-11-21\",\"2024-11-22\",\"2024-11-25\",\"2024-11-26\",\"2024-11-27\",\"2024-11-29\",\"2024-12-02\",\"2024-12-03\",\"2024-12-04\",\"2024-12-05\",\"2024-12-06\",\"2024-12-09\",\"2024-12-10\",\"2024-12-11\",\"2024-12-12\",\"2024-12-13\",\"2024-12-16\",\"2024-12-17\",\"2024-12-18\",\"2024-12-19\",\"2024-12-20\",\"2024-12-23\",\"2024-12-24\",\"2024-12-26\",\"2024-12-27\",\"2024-12-30\",\"2024-12-31\",\"2025-01-02\",\"2025-01-03\",\"2025-01-06\",\"2025-01-07\",\"2025-01-08\",\"2025-01-10\",\"2025-01-13\",\"2025-01-14\",\"2025-01-15\",\"2025-01-16\",\"2025-01-17\",\"2025-01-21\",\"2025-01-22\",\"2025-01-23\",\"2025-01-24\",\"2025-01-27\",\"2025-01-28\",\"2025-01-29\",\"2025-01-30\",\"2025-01-31\",\"2025-02-03\",\"2025-02-04\",\"2025-02-05\",\"2025-02-06\",\"2025-02-07\",\"2025-02-10\",\"2025-02-11\",\"2025-02-12\",\"2025-02-13\",\"2025-02-14\",\"2025-02-18\",\"2025-02-19\",\"2025-02-20\",\"2025-02-21\",\"2025-02-24\",\"2025-02-25\",\"2025-02-26\",\"2025-02-27\",\"2025-02-28\",\"2025-03-03\",\"2025-03-04\",\"2025-03-05\",\"2025-03-06\",\"2025-03-07\",\"2025-03-10\",\"2025-03-11\",\"2025-03-12\",\"2025-03-13\",\"2025-03-14\",\"2025-03-17\",\"2025-03-18\",\"2025-03-19\",\"2025-03-20\",\"2025-03-21\",\"2025-03-24\",\"2025-03-25\",\"2025-03-26\",\"2025-03-27\",\"2025-03-28\",\"2025-03-31\",\"2025-04-01\",\"2025-04-02\",\"2025-04-03\",\"2025-04-04\",\"2025-04-07\",\"2025-04-08\",\"2025-04-09\",\"2025-04-10\",\"2025-04-11\",\"2025-04-14\",\"2025-04-15\",\"2025-04-16\",\"2025-04-17\",\"2025-04-21\",\"2025-04-22\",\"2025-04-23\",\"2025-04-24\",\"2025-04-25\",\"2025-04-28\",\"2025-04-29\",\"2025-04-30\",\"2025-05-01\",\"2025-05-02\",\"2025-05-05\",\"2025-05-06\",\"2025-05-07\",\"2025-05-08\",\"2025-05-09\",\"2025-05-12\",\"2025-05-13\",\"2025-05-14\",\"2025-05-15\",\"2025-05-16\",\"2025-05-19\",\"2025-05-20\",\"2025-05-21\",\"2025-05-22\",\"2025-05-23\",\"2025-05-27\",\"2025-05-28\",\"2025-05-29\",\"2025-05-30\",\"2025-06-02\",\"2025-06-03\",\"2025-06-04\",\"2025-06-05\",\"2025-06-06\",\"2025-06-09\",\"2025-06-10\",\"2025-06-11\",\"2025-06-12\",\"2025-06-13\",\"2025-06-16\",\"2025-06-17\",\"2025-06-18\",\"2025-06-20\",\"2025-06-23\",\"2025-06-24\",\"2025-06-25\",\"2025-06-26\",\"2025-06-27\",\"2025-06-30\",\"2025-07-01\",\"2025-07-02\",\"2025-07-03\",\"2025-07-07\",\"2025-07-08\",\"2025-07-09\",\"2025-07-10\",\"2025-07-11\",\"2025-07-14\",\"2025-07-15\",\"2025-07-16\",\"2025-07-17\",\"2025-07-18\",\"2025-07-21\",\"2025-07-22\",\"2025-07-23\",\"2025-07-24\",\"2025-07-25\",\"2025-07-28\",\"2025-07-29\",\"2025-07-30\",\"2025-07-31\",\"2025-08-01\",\"2025-08-04\",\"2025-08-05\",\"2025-08-06\",\"2025-08-07\",\"2025-08-08\",\"2025-08-11\",\"2025-08-12\",\"2025-08-13\",\"2025-08-14\",\"2025-08-15\",\"2025-08-18\",\"2025-08-19\",\"2025-08-20\",\"2025-08-21\",\"2025-08-22\",\"2025-08-25\",\"2025-08-26\",\"2025-08-27\",\"2025-08-28\",\"2025-08-29\",\"2025-09-02\",\"2025-09-03\",\"2025-09-04\",\"2025-09-05\",\"2025-09-08\",\"2025-09-09\",\"2025-09-10\",\"2025-09-11\",\"2025-09-12\",\"2025-09-15\",\"2025-09-16\",\"2025-09-17\",\"2025-09-18\",\"2025-09-19\",\"2025-09-22\",\"2025-09-23\",\"2025-09-24\",\"2025-09-25\",\"2025-09-26\",\"2025-09-29\",\"2025-09-30\",\"2025-10-01\",\"2025-10-02\",\"2025-10-03\",\"2025-10-06\",\"2025-10-07\",\"2025-10-08\",\"2025-10-09\",\"2025-10-10\",\"2025-10-13\",\"2025-10-14\",\"2025-10-15\",\"2025-10-16\",\"2025-10-17\",\"2025-10-20\",\"2025-10-21\",\"2025-10-22\",\"2025-10-23\",\"2025-10-24\",\"2025-10-27\",\"2025-10-28\",\"2025-10-29\",\"2025-10-30\",\"2025-10-31\",\"2025-11-03\",\"2025-11-04\",\"2025-11-05\",\"2025-11-06\",\"2025-11-07\",\"2025-11-10\",\"2025-11-11\",\"2025-11-12\",\"2025-11-13\",\"2025-11-14\",\"2025-11-17\",\"2025-11-18\",\"2025-11-19\",\"2025-11-20\",\"2025-11-21\",\"2025-11-24\",\"2025-11-25\",\"2025-11-26\",\"2025-11-28\",\"2025-12-01\",\"2025-12-02\",\"2025-12-03\",\"2025-12-04\",\"2025-12-05\",\"2025-12-08\",\"2025-12-09\",\"2025-12-10\",\"2025-12-11\",\"2025-12-12\",\"2025-12-15\",\"2025-12-16\",\"2025-12-17\",\"2025-12-18\",\"2025-12-19\",\"2025-12-22\",\"2025-12-23\",\"2025-12-24\",\"2025-12-26\"],\n",
"\"price\":[108.71000000000001,109.72,109.88,107.53,109.06,108.77,108.3,109.3,107.67,108.62,110.39,109.4,107.51,108.64,108.81,110.48,109.69,109.69,109.03,108.09,107.64,106.55,106.53,105.05,104.81,102.86,101.46000000000001,98.75,97.63,98.84,99.63,101.77,102.10000000000001,101.71000000000001,102.36,100.32000000000001,100.18,97.93,97.67,96.79,96.3,96.13,97.19,96.26,95.51,94.62,94.04,91.59,90.85000000000001,90.60000000000001,90.17,89.42,89.63,95.62,94.56,95.09,95.89,95.79,97.11,96.88,97.62,98.65,99.25,99.91,102.04,103.01,103.77,103.05,102.67,102.81,105.18,103.54,100.02,97.98,101.8,102.77,100.88,105.08,107.06,107.25,109.36,109.39,107.0,106.11,104.2,105.75,107.82000000000001,107.61,105.96000000000001,106.32000000000001,106.55,107.92,107.64,107.96000000000001,108.75,110.37,110.27,113.48,115.15,115.41,116.11,114.81,115.91,118.61,119.64,121.17,121.02,121.55,121.14,122.64,121.43,122.53,108.04,108.02,107.13,108.82000000000001,108.57000000000001,106.55,104.04,102.3,102.08,103.62,102.74000000000001,103.77,105.9,105.06,101.72,100.82000000000001,100.94,101.78,100.56,101.9,100.76,100.77,102.75,103.88,104.18,101.53,101.76,100.71000000000001,99.68,102.61,103.79,103.77,104.5,107.18,105.0,106.33,106.05,103.51,103.3,105.27,105.08,105.63,104.54,105.15,104.35000000000001,103.93,101.88,99.54,98.31,97.63,98.19,99.16,101.08,100.18,101.36,100.26,99.64,98.74000000000001,99.96000000000001,100.27,100.82000000000001,93.86,93.75,92.58,94.13,93.98,92.56,90.95,90.33,89.07000000000001,88.84,90.0,91.0,89.0,92.0,92.0,93.10000000000001,93.39,94.84,95.74000000000001,94.53,94.19,94.02,94.64,93.94,94.12,94.06,92.26,90.34,92.41,92.15,93.36,93.78,93.59,93.39,90.94,92.72,92.79,91.67,91.77,92.18,91.77,92.82000000000001,92.5,91.4,91.75,92.0,91.67,93.45,95.05,94.4,94.74,94.32000000000001,95.72,96.55,96.0,95.87,93.68,94.18,93.39,95.0,94.78,95.57000000000001,97.18,97.17,94.75,94.06,94.19,75.37,76.83,76.04,75.23,75.43,73.05,72.45,72.54,73.39,73.42,71.31,72.81,73.06,72.38,72.7,74.86,73.4,71.09,71.41,72.56,73.55,74.31,74.86,73.84,74.01,71.42,72.5,72.62,74.19,74.34,74.64,78.5,78.52,82.5,83.23,83.28,83.56,84.0,83.41,84.05,84.28,85.29,82.79,83.26,83.32000000000001,81.31,81.02,80.83,80.63,79.48,78.09,78.4,78.4,79.01,79.8,80.64,80.9,80.98,86.52,86.2,87.46000000000001,88.0,89.39,89.44,88.4,89.13,83.10000000000001,82.10000000000001,82.25,80.83,80.77,82.45,82.10000000000001,82.15,81.59,82.12,83.94,83.4,82.92,81.48,81.42,80.05,79.04,78.84,78.91,78.4,76.45,77.13,78.06,77.19,77.98,75.31,75.92,75.88,76.59,76.66,76.52,75.68,76.66,74.89,73.91,73.36,75.09,77.4,79.26,77.61,78.34,78.77,79.09,78.86,78.37,78.58,78.89,77.64,76.73,78.84,77.95,77.25,77.2,78.0,76.9,77.09,76.94,76.76,76.79,76.94,76.42,74.65,75.67,73.67,73.31,72.0,72.09,71.29,71.2,72.08,71.17,71.06,71.11,70.84,73.17,74.04,74.29,73.56,75.58,74.39,76.58,78.33,76.9,76.59,76.72,74.56,71.73,68.68,70.94,71.34,72.26,73.2,73.04,77.59,76.78,77.23,76.5,80.28,81.72,81.17,80.02,79.43,78.41,77.31,77.81,77.7,78.59,76.4,74.17,73.58,72.64,71.66,73.7,73.31,72.98,71.86,67.94,67.39,66.54,65.73,65.8,63.29,63.480000000000004,64.76,64.95,55.58,57.25,55.61,53.27,59.32,54.4,54.39,55.410000000000004,54.83,53.550000000000004,55.76,56.120000000000005,57.06,57.39,58.480000000000004,57.620000000000005,57.31,57.54,56.4,56.76,58.59,57.35,57.04,58.620000000000005,58.910000000000004,58.300000000000004,62.58,62.39,61.730000000000004,62.4,63.11,62.08,62.56,59.980000000000004,61.32,60.02,62.83,61.78,61.44,60.59,61.57,62.370000000000005,62.77,62.67,62.800000000000004,61.910000000000004,63.870000000000005,63.11,62.800000000000004,60.53,61.9,60.0,59.51,59.79,60.78,61.42,60.83,62.54,72.04,71.04,73.41,76.39,76.39,76.53,73.92,73.56,74.62,72.63,72.25,71.98,72.09,72.98,72.47,74.02,75.39,76.75,75.42,76.27,79.23,78.33,76.68,74.69,74.62,74.81,74.38,75.48,74.34,74.19,74.02,74.9,77.2,76.39,76.97,77.43,76.88,76.26,76.18,78.38,79.17,78.65,78.06,77.92,77.37,74.29,74.73,75.34,73.91,74.15,73.59,74.25,74.33,73.0,73.03,72.75,72.31,72.09,70.89,71.28,70.93,71.22,69.23,69.31,69.55,69.73,74.2,74.56,71.93,71.17,68.91,69.09,68.06,65.22,67.38,67.64,68.45,66.84,67.37,67.62,68.36,69.08,69.68,69.11,68.59,67.43,65.34,64.9,64.59,62.65,61.230000000000004,62.11,61.89,61.09,60.800000000000004,63.15,64.2,66.03,64.17,62.9,62.49,62.64,61.43,62.800000000000004,61.93,63.68,64.33,64.63,65.39,64.93,65.65,65.69,65.86,63.54,63.33,65.79,67.73,67.47,67.78,67.12,65.69,65.63,58.71,57.22,57.34,60.0,60.93]\n",
"},\n",
"\"mapping\":{\n",
"\"x\":\"date\",\n",
"\"y\":\"price\"\n",
"},\n",
"\"data_meta\":{\n",
"},\n",
"\"color\":\"#f9fbfd\"\n",
"},{\n",
"\"geom\":\"point\",\n",
"\"data\":{\n",
"\"date\":[\"2023-10-02\",\"2024-06-28\",\"2025-04-04\",\"2025-12-22\"],\n",
"\"purchase_price\":[96.0,77.0,58.0,57.54]\n",
"},\n",
"\"mapping\":{\n",
"\"x\":\"date\",\n",
"\"y\":\"purchase_price\"\n",
"},\n",
"\"data_meta\":{\n",
"},\n",
"\"color\":\"#20c997\",\n",
"\"size\":6.0,\n",
"\"alpha\":0.8\n",
"}],\n",
"\"metainfo_list\":[]\n",
"};\n",
" var plotContainer = document.getElementById(\"z5dOE6\");\n",
" window.letsPlotCall(function() {{\n",
" LetsPlot.buildPlotFromProcessedSpecs(plotSpec, -1, -1, plotContainer);\n",
" }});\n",
" })();\n",
" </script>"
],
"text/plain": [
"<lets_plot.plot.core.PlotSpec at 0x75ba1d48dfd0>"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Boilerplate theme colors and code\n",
"DARK_THEME = {\n",
" \"red\": \"#dc3545\",\n",
" \"yellow\": \"#ffc107\",\n",
" \"teal\": \"#20c997\",\n",
" \"blue_medium\": \"#53a5d5\",\n",
" \"blue_light\": \"#b5d5e1\",\n",
" \"black\": \"#161c2d\",\n",
" \"gray_medium\": \"#748196\",\n",
" \"gray_light\": \"#f9fbfd\",\n",
"}\n",
"\n",
"def dark_theme(colors: dict, show_legend: bool=True):\n",
" \"\"\"Create a dark theme for lets-plot.\"\"\"\n",
" t = lp.theme_none() + lp.theme(\n",
" plot_background=lp.element_rect(fill=colors[\"black\"]),\n",
" panel_background=lp.element_rect(fill=colors[\"black\"]),\n",
" panel_grid_major=lp.element_blank(),\n",
" panel_grid_minor=lp.element_blank(),\n",
" line=lp.element_line(color=colors[\"gray_light\"], size=3),\n",
" rect=lp.element_rect(color=colors[\"black\"], fill=colors[\"black\"], size=2),\n",
" text=lp.element_text(color=colors[\"gray_light\"], size=10),\n",
" axis_ontop=True,\n",
" axis_line=lp.element_line(color=colors[\"gray_light\"], size=3),\n",
" axis_ticks=lp.element_line(color=colors[\"gray_light\"], size=1),\n",
" axis_tooltip=lp.element_rect(color=colors[\"gray_light\"]),\n",
" tooltip=lp.element_rect(color=colors[\"gray_light\"], fill=colors[\"black\"]),\n",
" legend_background=lp.element_rect(color=colors[\"gray_light\"], fill=colors[\"black\"], size=2),\n",
" plot_title=lp.element_text(hjust=0.5, size=16, color=colors[\"gray_light\"]),\n",
" )\n",
" if show_legend:\n",
" return t + lp.theme(legend_position=\"bottom\")\n",
" else:\n",
" return t + lp.theme(legend_position=\"none\")\n",
"\n",
"p = (\n",
" lp.ggplot()\n",
" + lp.geom_line(data=combo_df, mapping=lp.aes(x=\"date\", y=\"price\"), color=DARK_THEME[\"gray_light\"])\n",
" + lp.geom_point(\n",
" data=combo_df.filter(pl.col(\"transaction_code\") == \"P\"),\n",
" mapping=lp.aes(x=\"date\", y=\"purchase_price\"),\n",
" color=DARK_THEME[\"teal\"],\n",
" size=6,\n",
" alpha=0.8\n",
" )\n",
" + lp.ggtitle(\"NKE Stock Price with Robert Holmes Swan Purchases\")\n",
" + lp.labs(x=\"Date\", y=\"Price (USD)\")\n",
" + lp.ggsize(800, 500)\n",
" + lp.scale_y_continuous(position=\"right\")\n",
" + lp.scale_x_discrete(expand=[0.05, 0])\n",
" + dark_theme(DARK_THEME)\n",
")\n",
"p"
]
},
{
"cell_type": "markdown",
"id": "332f07c5",
"metadata": {},
"source": [
"While NKE stock has consistently been in a downtrend, we can see that Bob Swan's buys have proven to be excellent price levels for taking a short-term trade:\n",
"- 2023-10-02, bought at 96.00, price rallied above 123.00 (+28%) within 3 months, zero drawdown\n",
"- 2024-06-28, bought at 77.00, price rallied above 89.00 (+15%) within 3 months, less than -10% drawdown\n",
"- 2025-04-04, bought at 58.00, price rallied above 76.00 (+31%) within 3 months, less than -10% drawdown\n",
"- 2025-12-22, bought at 57.54, price above 61.00 (+6%) within the last week, zero drawdown"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "dans-magic-house",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment