Created
December 27, 2025 19:55
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "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>"d4a833c5-92ae-401d-b0ba-cb0585…</td><td>"NKE"</td><td>8691</td><td>1</td><td>"57.5400"</td><td>"Consumer Cyclical"</td><td>"72464878318"</td><td>"2026-03-19"</td><td>true</td><td>"2025-12-22"</td><td>"2025-12-23"</td><td>true</td><td>false</td><td>false</td><td>false</td><td>"60.93"</td><td>"Class B Common Stock"</td><td>"4"</td><td>"P"</td><td>false</td><td>"SWAN ROBERT HOLMES"</td><td>"NA"</td><td>43293</td><td>null</td><td>34602</td><td>"D"</td><td>null</td><td>null</td><td>null</td><td>null</td><td>["1fc22d5d-1f1b-450a-92bb-2ff050e8a6ba"]</td></tr><tr><td>"93fd147e-320f-4bb2-84a0-cb9015…</td><td>"NKE"</td><td>50000</td><td>1</td><td>"58.9700"</td><td>"Consumer Cyclical"</td><td>"72464878318"</td><td>"2026-03-19"</td><td>true</td><td>"2025-12-22"</td><td>"2025-12-23"</td><td>true</td><td>false</td><td>false</td><td>false</td><td>"60.93"</td><td>"Class B Common Stock"</td><td>"4"</td><td>"P"</td><td>false</td><td>"COOK TIMOTHY"</td><td>"NA"</td><td>105480</td><td>null</td><td>55480</td><td>"D"</td><td>null</td><td>null</td><td>null</td><td>null</td><td>["27920e26-5e6b-4690-969b-ffa2a98ec246"]</td></tr><tr><td>"358cf67c-b74d-410b-a654-79f650…</td><td>"NKE"</td><td>36645</td><td>2</td><td>"0.0000"</td><td>"Consumer Cyclical"</td><td>"72464878318"</td><td>"2026-03-19"</td><td>true</td><td>"2025-12-10"</td><td>"2025-12-16"</td><td>false</td><td>true</td><td>false</td><td>false</td><td>"60.93"</td><td>"Class B Common Stock"</td><td>"4"</td><td>"A"</td><td>false</td><td>"ALAGIRISAMY VENKATESH"</td><td>"NA"</td><td>86040</td><td>"EVP: CHIEF OPERATING OFFICER"</td><td>49395</td><td>"D"</td><td>null</td><td>null</td><td>null</td><td>null</td><td>["c5a0ba7e-9c23-424d-87e4-491cc16c5858", "1bceeaa4-a9ab-4b33-96f5-77242482e969"]</td></tr><tr><td>"70683e11-4ff9-4bc4-a666-c7dd0d…</td><td>"NKE"</td><td>17615</td><td>1</td><td>"65.7900"</td><td>"Consumer Cyclical"</td><td>"72464878318"</td><td>"2026-03-19"</td><td>true</td><td>"2025-12-10"</td><td>"2025-12-16"</td><td>false</td><td>true</td><td>false</td><td>false</td><td>"60.93"</td><td>"Non-Qualified Stock Option (Ri…</td><td>"4"</td><td>"A"</td><td>false</td><td>"ALAGIRISAMY VENKATESH"</td><td>"DA"</td><td>17615</td><td>"EVP: CHIEF OPERATING OFFICER"</td><td>0</td><td>"D"</td><td>null</td><td>null</td><td>"65.79"</td><td>"2035-12-10"</td><td>["50240147-a223-426f-9283-6433e69368c6"]</td></tr><tr><td>"f2ee1726-3a42-4622-a947-00216c…</td><td>"NKE"</td><td>31216</td><td>1</td><td>"0.0000"</td><td>"Consumer Cyclical"</td><td>"72464878318"</td><td>"2026-03-19"</td><td>true</td><td>"2025-12-10"</td><td>"2025-12-12"</td><td>false</td><td>true</td><td>false</td><td>false</td><td>"60.93"</td><td>"Class B Common Stock"</td><td>"4"</td><td>"A"</td><td>false</td><td>"FRIEND MATTHEW"</td><td>"NA"</td><td>85530</td><td>"EVP: CFO"</td><td>54314</td><td>"D"</td><td>null</td><td>null</td><td>null</td><td>null</td><td>["8e733519-6e85-4d16-9db5-1bd17aa1a568"]</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>"2023-10-02"</td><td>9600</td><td>13072</td><td>"P"</td></tr><tr><td>"2024-06-28"</td><td>7700</td><td>2941</td><td>"P"</td></tr><tr><td>"2025-04-04"</td><td>5800</td><td>8600</td><td>"P"</td></tr><tr><td>"2025-12-22"</td><td>5754</td><td>8691</td><td>"P"</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>"2023-07-17"</td><td>10871</td></tr><tr><td>"2023-07-18"</td><td>10972</td></tr><tr><td>"2023-07-19"</td><td>10988</td></tr><tr><td>"2023-07-20"</td><td>10753</td></tr><tr><td>"2023-07-21"</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>"2025-12-19"</td><td>5871</td><td>null</td><td>null</td><td>null</td><td>58.71</td><td>null</td></tr><tr><td>"2025-12-22"</td><td>5722</td><td>8691</td><td>5754</td><td>"P"</td><td>57.22</td><td>57.54</td></tr><tr><td>"2025-12-23"</td><td>5734</td><td>null</td><td>null</td><td>null</td><td>57.34</td><td>null</td></tr><tr><td>"2025-12-24"</td><td>6000</td><td>null</td><td>null</td><td>null</td><td>60.0</td><td>null</td></tr><tr><td>"2025-12-26"</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