Skip to content

Instantly share code, notes, and snippets.

@Metaomniliquant
Created August 27, 2024 13:12
Show Gist options
  • Save Metaomniliquant/2d00a5bdd7aacacb115a2a6cb13b3111 to your computer and use it in GitHub Desktop.
Save Metaomniliquant/2d00a5bdd7aacacb115a2a6cb13b3111 to your computer and use it in GitHub Desktop.
PowerShell Stock Alerts
@{
# Script module or binary module file associated with this manifest.
RootModule = 'stock_alert_api.psm1'
# Version number of this module.
ModuleVersion = '1.0.0'
# ID used to uniquely identify this module
GUID = 'e8b0320d-8f4d-4c5f-b4ea-fd9c4a7c6e99'
# Author of this module
Author = 'Caleb McElrath'
# Copyright statement for this module
Copyright = '© 2024 Caleb McElrath. All rights reserved.'
# Description of the functionality provided by this module
Description = 'This module provides functionality for processing stock information and generating notifications upon upward and downward trend criteria.'
# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '5.1'
# Functions to export from this module
FunctionsToExport = @('Start-SymbolProcess', 'New-SymbolProcessParameters')
# List of all files packaged with this module
FileList = @('stock_alert_api.psm1')
# Whether this module requires elevated permissions to run
PowerShellHostName = @('ConsoleHost')
# End of manifest
}
Import-Module BurntToast
class SymbolProcessParameters {
[string]$SymbolFile
[string]$ApiKey
[int]$DownTrendDays
[int]$DownTrendPct
[int]$UpTrendDays
[int]$UpTrendPct
[ScriptBlock]$GetCurrentDate
[ScriptBlock]$GetSymbolList
[ScriptBlock]$DataProvider
[ScriptBlock]$NotificationProvider
SymbolProcessParameters() {
$this.GetCurrentDate = {
(Get-Date).AddDays(-4)
}
$this.GetSymbolList = {
param($symbolFile)
Get-Content $symbolFile
}
$this.DataProvider = {
param($url)
Invoke-RestMethod -Uri $url -Method Get
}
$this.NotificationProvider = {
param($message)
New-BurntToastNotification -Text "Buy The Dip Alert", $message
}
}
}
function New-SymbolProcessParameters {
return [SymbolProcessParameters]::new()
}
function Get-CurrentDate {
param (
[ScriptBlock]$GetCurrentDate = {
(Get-Date).AddDays(-4)
}
)
return (& $GetCurrentDate)
}
function Get-SymbolList {
param (
[string]$symbolFile,
[ScriptBlock]$GetSymbolList = {
param($symbolFile)
Get-Content $symbolFile
}
)
return (& $GetSymbolList $symbolFile)
}
function Get-StockData {
param (
[string]$symbol,
[string]$apiKey,
[ScriptBlock]$DataProvider = {
param($url)
Invoke-RestMethod -Uri $url -Method Get
}
)
$url = "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=$symbol&apikey=$apiKey"
try {
return (& $DataProvider $url)."Time Series (Daily)"
} catch {
Write-Error "Failed to retrieve data for $symbol"
return $null
}
}
function ConvertTo-DataFrame {
param (
[PSCustomObject]$data
)
$df = @()
foreach ($dateMember in $data.PSObject.Properties.Name) {
$row = [PSCustomObject]@{
ActivityDate = [datetime]::Parse($dateMember)
ClosePrice = $data.$dateMember."4. close"
Pct_Change_Downtrend = 0
Pct_Change_Uptrend = 0
}
$df += $row
}
return $df | Sort-Object ActivityDate
}
function Set-PercentageChanges {
param (
[array]$dataFrame,
[int]$downTrendDays,
[int]$upTrendDays
)
for ($i = $downTrendDays; $i -lt $dataFrame.Count; $i++) {
$dataFrame[$i].Pct_Change_Downtrend = (($dataFrame[$i].ClosePrice - $dataFrame[$i - $downTrendDays].ClosePrice) / $dataFrame[$i - $downTrendDays].ClosePrice) * 100
}
for ($i = $upTrendDays; $i -lt $dataFrame.Count; $i++) {
$dataFrame[$i].Pct_Change_Uptrend = (($dataFrame[$i].ClosePrice - $dataFrame[$i - $upTrendDays].ClosePrice) / $dataFrame[$i - $upTrendDays].ClosePrice) * 100
}
return $dataFrame
}
function Get-Alerts {
param (
[array]$dataFrame,
[int]$downTrendPct,
[int]$upTrendPct,
[datetime]$alertThresholdDate
)
$alerts = $dataFrame | Where-Object {
$_.Pct_Change_Downtrend -le $downTrendPct -and $_.Pct_Change_Uptrend -ge $upTrendPct -and $_.ActivityDate -ge $alertThresholdDate
}
return $alerts
}
function Send-Notification {
param (
[string]$symbol,
[PSCustomObject]$alert,
[int]$downTrendPct,
[int]$downTrendDays,
[int]$upTrendPct,
[int]$upTrendDays,
[ScriptBlock]$NotificationProvider = {
param($message)
New-BurntToastNotification -Text "Buy The Dip Alert", $message
}
)
$activityDate = $alert.ActivityDate.ToString("M/dd")
$message = "$activityDate : $symbol has declined by $downTrendPct% over $downTrendDays days and increased by $upTrendPct% within $upTrendDays days."
& $NotificationProvider $message
}
function Start-SymbolProcess {
param (
[SymbolProcessParameters]$Params
)
$alertThresholdDate = Get-CurrentDate -GetCurrentDate $Params.GetCurrentDate
$symbols = Get-SymbolList -symbolFile $Params.SymbolFile -GetSymbolList $Params.GetSymbolList
foreach ($symbol in $symbols) {
# Get the stock data using the Get-StockData function
$data = Get-StockData -symbol $symbol -apiKey $Params.ApiKey -DataProvider $Params.DataProvider
# Skip processing if data retrieval failed
if (-not $data) {
continue
}
$df = ConvertTo-DataFrame -data $data
$df = Set-PercentageChanges -dataFrame $df -downTrendDays $Params.DownTrendDays -upTrendDays $Params.UpTrendDays
$alerts = Get-Alerts -dataFrame $df -downTrendPct $Params.DownTrendPct -upTrendPct $Params.UpTrendPct -alertThresholdDate $alertThresholdDate
foreach ($alert in $alerts) {
Send-Notification -symbol $symbol -alert $alert -downTrendPct $Params.DownTrendPct -downTrendDays $Params.DownTrendDays -upTrendPct $Params.UpTrendPct -upTrendDays $Params.UpTrendDays -NotificationProvider $Params.NotificationProvider
}
}
}
Export-ModuleMember -Function Start-SymbolProcess, New-SymbolProcessParameters
# Import the module to be tested
Import-Module -Name "./stock_alert_api" -Verbose
Describe "Start-SymbolProcess" {
BeforeAll {
$testCurrentDate = {
return Get-Date "2024-08-01"
}
$testDataProvider = {
$json = '{
"Time Series (Daily)": {
"2024-08-06": { "4. close": "522.1500" },
"2024-08-05": { "4. close": "517.3800" },
"2024-08-02": { "4. close": "532.9000" },
"2024-08-01": { "4. close": "543.0100" },
"2024-07-31": { "4. close": "550.8100" },
"2024-07-30": { "4. close": "542.0000" },
"2024-07-29": { "4. close": "544.7600" },
"2024-07-26": { "4. close": "544.4400" },
"2024-07-25": { "4. close": "538.4100" },
"2024-07-24": { "4. close": "541.2300" },
"2024-07-23": { "4. close": "553.7800" },
"2024-07-22": { "4. close": "554.6500" },
"2024-07-19": { "4. close": "548.9900" },
"2024-07-18": { "4. close": "552.6600" },
"2024-07-17": { "4. close": "556.9400" }
}
}'
return $json | ConvertFrom-Json
}
$testGetSymbolList = {
return @("AAPL", "MSFT")
}
$global:notificationsSent = @()
$testNotificationProvider = {
param($message)
$global:notificationsSent += $message
}
}
BeforeEach {
# Clear notifications before each test
$global:notificationsSent = @()
}
It "Should process symbols and send notifications for valid alerts" {
# Prepare test parameters
$params = New-SymbolProcessParameters
$params.SymbolFile = "fake_symbols.txt"
$params.ApiKey = "test_api_key"
$params.DownTrendDays = 14
$params.DownTrendPct = -6
$params.UpTrendDays = 1
$params.UpTrendPct = 0
$params.GetCurrentDate = $testCurrentDate
$params.GetSymbolList = $testGetSymbolList
$params.DataProvider = $testDataProvider
$params.NotificationProvider = $testNotificationProvider
# Execute the function
Start-SymbolProcess -Params $params
# Verify that notifications were sent
$global:notificationsSent | Should -HaveCount 2
$global:notificationsSent | Should -Contain "8/06 : AAPL has declined by -6% over 14 days and increased by 0% within 1 days."
$global:notificationsSent | Should -Contain "8/06 : MSFT has declined by -6% over 14 days and increased by 0% within 1 days."
}
It "Should skip processing if no alerts match the criteria" {
$testCurrentDate = {
return Get-Date "2024-07-26" # exclude alerts due to the date threshold
}
$testDataProvider = {
$json = '{
"Time Series (Daily)": {
"2024-07-25": { "4. close": "550.4100" },
"2024-07-24": { "4. close": "400.2300" },
"2024-07-23": { "4. close": "500.7800" },
"2024-07-22": { "4. close": "530.6500" },
"2024-07-19": { "4. close": "560.9900" },
"2024-07-18": { "4. close": "600.6600" }
}
}'
return $json | ConvertFrom-Json
}
# Prepare test parameters
$params = New-SymbolProcessParameters
$params.SymbolFile = "fake_symbols.txt"
$params.ApiKey = "test_api_key"
$params.DownTrendDays = 5
$params.DownTrendPct = -6
$params.UpTrendDays = 1
$params.UpTrendPct = 0
$params.GetCurrentDate = $testCurrentDate
$params.GetSymbolList = $testGetSymbolList
$params.DataProvider = $testDataProvider
$params.NotificationProvider = $testNotificationProvider
# Execute the function
Start-SymbolProcess -Params $params
# Verify that no notifications were sent
$global:notificationsSent | Should -BeNullOrEmpty
}
It "Should handle multiple symbols and generate alerts correctly" {
# Prepare test parameters
$params = New-SymbolProcessParameters
$params.SymbolFile = "fake_symbols.txt"
$params.ApiKey = "test_api_key"
$params.DownTrendDays = 14
$params.DownTrendPct = -6
$params.UpTrendDays = 1
$params.UpTrendPct = 0
$params.GetCurrentDate = $testCurrentDate
$params.GetSymbolList = {
return @("AAPL", "GOOGL", "AMZN")
}
$params.DataProvider = $testDataProvider
$params.NotificationProvider = $testNotificationProvider
# Execute the function
Start-SymbolProcess -Params $params
# Verify that notifications were sent for all symbols
$global:notificationsSent | Should -HaveCount 3
}
It "Should skip processing when data retrieval fails" {
# Simulate data provider failure
$failingDataProvider = { return $null }
# Prepare test parameters
$params = New-SymbolProcessParameters
$params.SymbolFile = "fake_symbols.txt"
$params.ApiKey = "test_api_key"
$params.DownTrendDays = 14
$params.DownTrendPct = -6
$params.UpTrendDays = 1
$params.UpTrendPct = 0
$params.GetCurrentDate = $testCurrentDate
$params.GetSymbolList = $testGetSymbolList
$params.DataProvider = $failingDataProvider
$params.NotificationProvider = $testNotificationProvider
# Execute the function
Start-SymbolProcess -Params $params
# Verify that no notifications were sent due to data retrieval failure
$global:notificationsSent | Should -BeNullOrEmpty
}
}
SPY
QQQ
DIA
IWM
{
"Time Series (Daily)": {
"2024-08-23": {
"1. open": "559.5300",
"2. high": "563.0900",
"3. low": "557.2900",
"4. close": "562.1300",
"5. volume": "50639393"
},
"2024-08-22": {
"1. open": "562.5600",
"2. high": "563.1800",
"3. low": "554.9800",
"4. close": "556.2200",
"5. volume": "56121456"
},
"2024-08-21": {
"1. open": "559.7700",
"2. high": "562.1100",
"3. low": "554.7300",
"4. close": "560.6200",
"5. volume": "41514600"
},
"2024-08-20": {
"1. open": "559.1500",
"2. high": "560.8400",
"3. low": "557.3250",
"4. close": "558.7000",
"5. volume": "33732264"
},
"2024-08-19": {
"1. open": "554.7300",
"2. high": "559.6100",
"3. low": "553.8600",
"4. close": "559.6100",
"5. volume": "39121793"
},
"2024-08-16": {
"1. open": "551.4200",
"2. high": "555.0200",
"3. low": "551.2600",
"4. close": "554.3100",
"5. volume": "44430728"
},
"2024-08-15": {
"1. open": "549.5000",
"2. high": "553.3600",
"3. low": "548.8800",
"4. close": "553.0700",
"5. volume": "60846812"
},
"2024-08-14": {
"1. open": "542.8500",
"2. high": "544.9600",
"3. low": "540.1200",
"4. close": "543.7500",
"5. volume": "42446929"
},
"2024-08-13": {
"1. open": "536.5300",
"2. high": "542.2800",
"3. low": "536.2800",
"4. close": "542.0400",
"5. volume": "52333073"
},
"2024-08-12": {
"1. open": "534.2100",
"2. high": "535.7300",
"3. low": "530.9500",
"4. close": "533.2700",
"5. volume": "42542069"
},
"2024-08-09": {
"1. open": "529.8100",
"2. high": "534.5100",
"3. low": "528.5600",
"4. close": "532.9900",
"5. volume": "45619558"
},
"2024-08-08": {
"1. open": "523.9100",
"2. high": "531.2900",
"3. low": "521.8400",
"4. close": "530.6500",
"5. volume": "63276589"
},
"2024-08-07": {
"1. open": "528.4700",
"2. high": "531.5900",
"3. low": "518.0519",
"4. close": "518.6600",
"5. volume": "70698340"
},
"2024-08-06": {
"1. open": "519.2200",
"2. high": "529.7500",
"3. low": "517.8700",
"4. close": "522.1500",
"5. volume": "84826312"
},
"2024-08-05": {
"1. open": "511.6400",
"2. high": "523.5800",
"3. low": "510.2700",
"4. close": "517.3800",
"5. volume": "146267391"
},
"2024-08-02": {
"1. open": "535.7500",
"2. high": "536.9900",
"3. low": "528.6000",
"4. close": "532.9000",
"5. volume": "82789070"
},
"2024-08-01": {
"1. open": "552.5700",
"2. high": "554.8688",
"3. low": "539.4300",
"4. close": "543.0100",
"5. volume": "76428732"
},
"2024-07-31": {
"1. open": "548.9800",
"2. high": "553.5000",
"3. low": "547.5799",
"4. close": "550.8100",
"5. volume": "65663388"
},
"2024-07-30": {
"1. open": "546.2600",
"2. high": "547.3400",
"3. low": "538.5150",
"4. close": "542.0000",
"5. volume": "46853632"
},
"2024-07-29": {
"1. open": "546.0200",
"2. high": "547.0500",
"3. low": "542.7200",
"4. close": "544.7600",
"5. volume": "39515824"
},
"2024-07-26": {
"1. open": "542.2800",
"2. high": "547.1900",
"3. low": "541.4900",
"4. close": "544.4400",
"5. volume": "53763788"
},
"2024-07-25": {
"1. open": "541.3500",
"2. high": "547.4550",
"3. low": "537.4500",
"4. close": "538.4100",
"5. volume": "61158288"
},
"2024-07-24": {
"1. open": "548.8600",
"2. high": "549.1700",
"3. low": "540.2900",
"4. close": "541.2300",
"5. volume": "74515266"
},
"2024-07-23": {
"1. open": "554.5400",
"2. high": "556.7350",
"3. low": "553.2750",
"4. close": "553.7800",
"5. volume": "34439561"
},
"2024-07-22": {
"1. open": "553.0000",
"2. high": "555.2700",
"3. low": "551.0200",
"4. close": "554.6500",
"5. volume": "43346720"
},
"2024-07-19": {
"1. open": "552.4200",
"2. high": "554.0800",
"3. low": "547.9100",
"4. close": "548.9900",
"5. volume": "65509081"
},
"2024-07-18": {
"1. open": "558.5100",
"2. high": "559.5200",
"3. low": "550.4300",
"4. close": "552.6600",
"5. volume": "56270392"
},
"2024-07-17": {
"1. open": "558.8000",
"2. high": "560.5100",
"3. low": "556.6100",
"4. close": "556.9400",
"5. volume": "57118956"
},
"2024-07-16": {
"1. open": "562.8650",
"2. high": "565.1600",
"3. low": "562.1000",
"4. close": "564.8600",
"5. volume": "36475260"
},
"2024-07-15": {
"1. open": "562.0300",
"2. high": "564.8371",
"3. low": "559.6300",
"4. close": "561.5300",
"5. volume": "40584293"
},
"2024-07-12": {
"1. open": "557.6300",
"2. high": "563.6700",
"3. low": "557.1500",
"4. close": "559.9900",
"5. volume": "53084405"
},
"2024-07-11": {
"1. open": "561.4400",
"2. high": "562.3300",
"3. low": "555.8300",
"4. close": "556.4800",
"5. volume": "53054184"
},
"2024-07-10": {
"1. open": "557.0700",
"2. high": "561.6700",
"3. low": "556.7700",
"4. close": "561.3200",
"5. volume": "38701220"
},
"2024-07-09": {
"1. open": "556.2600",
"2. high": "557.1800",
"3. low": "555.5200",
"4. close": "555.8200",
"5. volume": "27314125"
},
"2024-07-08": {
"1. open": "555.4400",
"2. high": "556.2501",
"3. low": "554.1900",
"4. close": "555.2800",
"5. volume": "36110451"
},
"2024-07-05": {
"1. open": "551.7700",
"2. high": "555.0500",
"3. low": "551.1200",
"4. close": "554.6400",
"5. volume": "41488389"
},
"2024-07-03": {
"1. open": "548.6900",
"2. high": "551.8300",
"3. low": "548.6500",
"4. close": "551.4600",
"5. volume": "32789911"
},
"2024-07-02": {
"1. open": "543.7000",
"2. high": "549.0100",
"3. low": "543.6500",
"4. close": "549.0100",
"5. volume": "40434792"
},
"2024-07-01": {
"1. open": "545.6300",
"2. high": "545.8800",
"3. low": "542.5200",
"4. close": "545.3400",
"5. volume": "40297810"
},
"2024-06-28": {
"1. open": "547.1600",
"2. high": "550.2800",
"3. low": "542.9500",
"4. close": "544.2200",
"5. volume": "76144535"
},
"2024-06-27": {
"1. open": "545.3700",
"2. high": "546.9600",
"3. low": "544.6100",
"4. close": "546.3700",
"5. volume": "35041480"
},
"2024-06-26": {
"1. open": "543.6900",
"2. high": "546.2400",
"3. low": "543.0300",
"4. close": "545.5100",
"5. volume": "38550637"
},
"2024-06-25": {
"1. open": "543.9900",
"2. high": "545.2000",
"3. low": "542.4400",
"4. close": "544.8300",
"5. volume": "38273346"
},
"2024-06-24": {
"1. open": "544.3300",
"2. high": "546.9500",
"3. low": "542.6200",
"4. close": "542.7400",
"5. volume": "45528654"
},
"2024-06-21": {
"1. open": "544.4000",
"2. high": "545.6500",
"3. low": "543.0200",
"4. close": "544.5100",
"5. volume": "64513859"
},
"2024-06-20": {
"1. open": "549.4400",
"2. high": "550.1200",
"3. low": "545.1800",
"4. close": "547.0000",
"5. volume": "70328226"
},
"2024-06-18": {
"1. open": "547.1600",
"2. high": "548.6200",
"3. low": "546.7300",
"4. close": "548.4900",
"5. volume": "41376417"
},
"2024-06-17": {
"1. open": "542.0800",
"2. high": "548.5300",
"3. low": "541.6072",
"4. close": "547.1000",
"5. volume": "55839457"
},
"2024-06-14": {
"1. open": "540.8800",
"2. high": "542.8100",
"3. low": "539.8500",
"4. close": "542.7800",
"5. volume": "40089895"
},
"2024-06-13": {
"1. open": "543.1500",
"2. high": "543.3250",
"3. low": "539.5900",
"4. close": "542.4500",
"5. volume": "44760949"
},
"2024-06-12": {
"1. open": "541.6300",
"2. high": "544.1200",
"3. low": "540.3000",
"4. close": "541.3600",
"5. volume": "63251305"
},
"2024-06-11": {
"1. open": "534.0700",
"2. high": "537.0100",
"3. low": "532.0500",
"4. close": "536.9500",
"5. volume": "36383411"
},
"2024-06-10": {
"1. open": "533.1800",
"2. high": "535.9900",
"3. low": "532.5700",
"4. close": "535.6600",
"5. volume": "35729252"
},
"2024-06-07": {
"1. open": "533.6600",
"2. high": "536.8900",
"3. low": "532.5350",
"4. close": "534.0100",
"5. volume": "43224525"
},
"2024-06-06": {
"1. open": "534.9800",
"2. high": "535.4200",
"3. low": "532.6800",
"4. close": "534.6600",
"5. volume": "30808530"
},
"2024-06-05": {
"1. open": "530.7700",
"2. high": "534.6900",
"3. low": "528.7254",
"4. close": "534.6700",
"5. volume": "47610365"
},
"2024-06-04": {
"1. open": "526.4600",
"2. high": "529.1500",
"3. low": "524.9600",
"4. close": "528.3900",
"5. volume": "34632661"
},
"2024-06-03": {
"1. open": "529.0200",
"2. high": "529.3100",
"3. low": "522.6000",
"4. close": "527.8000",
"5. volume": "46835702"
},
"2024-05-31": {
"1. open": "523.5900",
"2. high": "527.5000",
"3. low": "518.3600",
"4. close": "527.3700",
"5. volume": "90785755"
},
"2024-05-30": {
"1. open": "524.5200",
"2. high": "525.2000",
"3. low": "521.3300",
"4. close": "522.6100",
"5. volume": "46468510"
},
"2024-05-29": {
"1. open": "525.6800",
"2. high": "527.3100",
"3. low": "525.3700",
"4. close": "526.1000",
"5. volume": "45190323"
},
"2024-05-28": {
"1. open": "530.2700",
"2. high": "530.5100",
"3. low": "527.1100",
"4. close": "529.8100",
"5. volume": "36269602"
},
"2024-05-24": {
"1. open": "527.8500",
"2. high": "530.2700",
"3. low": "526.8810",
"4. close": "529.4400",
"5. volume": "41291076"
},
"2024-05-23": {
"1. open": "532.9600",
"2. high": "533.0700",
"3. low": "524.7200",
"4. close": "525.9600",
"5. volume": "57211197"
},
"2024-05-22": {
"1. open": "530.6500",
"2. high": "531.3800",
"3. low": "527.6000",
"4. close": "529.8300",
"5. volume": "48389968"
},
"2024-05-21": {
"1. open": "529.2800",
"2. high": "531.5200",
"3. low": "529.0700",
"4. close": "531.3600",
"5. volume": "33437001"
},
"2024-05-20": {
"1. open": "529.5700",
"2. high": "531.5601",
"3. low": "529.1700",
"4. close": "530.0600",
"5. volume": "37764206"
},
"2024-05-17": {
"1. open": "528.8100",
"2. high": "529.5200",
"3. low": "527.3200",
"4. close": "529.4500",
"5. volume": "59187585"
},
"2024-05-16": {
"1. open": "529.8800",
"2. high": "531.5218",
"3. low": "528.5400",
"4. close": "528.6900",
"5. volume": "50244827"
},
"2024-05-15": {
"1. open": "525.8300",
"2. high": "530.0800",
"3. low": "525.1800",
"4. close": "529.7800",
"5. volume": "59504897"
},
"2024-05-14": {
"1. open": "521.1100",
"2. high": "523.8300",
"3. low": "520.5600",
"4. close": "523.3000",
"5. volume": "57535867"
},
"2024-05-13": {
"1. open": "522.5600",
"2. high": "522.6700",
"3. low": "519.7400",
"4. close": "520.9100",
"5. volume": "36716361"
},
"2024-05-10": {
"1. open": "521.8100",
"2. high": "522.6350",
"3. low": "519.5900",
"4. close": "520.8400",
"5. volume": "52233171"
},
"2024-05-09": {
"1. open": "517.3800",
"2. high": "520.2074",
"3. low": "516.7050",
"4. close": "520.1700",
"5. volume": "43643668"
},
"2024-05-08": {
"1. open": "515.2600",
"2. high": "517.7400",
"3. low": "515.1400",
"4. close": "517.1900",
"5. volume": "42047214"
},
"2024-05-07": {
"1. open": "517.5600",
"2. high": "518.5700",
"3. low": "516.4500",
"4. close": "517.1400",
"5. volume": "52561299"
},
"2024-05-06": {
"1. open": "513.7500",
"2. high": "516.6100",
"3. low": "513.3000",
"4. close": "516.5700",
"5. volume": "47264703"
},
"2024-05-03": {
"1. open": "511.1600",
"2. high": "512.5500",
"3. low": "508.5600",
"4. close": "511.2900",
"5. volume": "72756709"
},
"2024-05-02": {
"1. open": "504.1500",
"2. high": "505.8900",
"3. low": "499.5500",
"4. close": "505.0300",
"5. volume": "62550179"
},
"2024-05-01": {
"1. open": "501.3800",
"2. high": "508.1900",
"3. low": "499.8650",
"4. close": "500.3500",
"5. volume": "80242839"
},
"2024-04-30": {
"1. open": "508.5600",
"2. high": "509.5600",
"3. low": "501.9800",
"4. close": "501.9800",
"5. volume": "77483566"
},
"2024-04-29": {
"1. open": "510.0900",
"2. high": "510.7500",
"3. low": "507.2500",
"4. close": "510.0600",
"5. volume": "46415449"
},
"2024-04-26": {
"1. open": "506.3500",
"2. high": "509.8800",
"3. low": "505.7000",
"4. close": "508.2600",
"5. volume": "64306118"
},
"2024-04-25": {
"1. open": "499.1800",
"2. high": "504.2700",
"3. low": "497.4900",
"4. close": "503.4900",
"5. volume": "69122368"
},
"2024-04-24": {
"1. open": "506.5600",
"2. high": "507.3700",
"3. low": "503.1300",
"4. close": "505.4100",
"5. volume": "55928076"
},
"2024-04-23": {
"1. open": "501.7800",
"2. high": "506.0900",
"3. low": "499.5328",
"4. close": "505.6500",
"5. volume": "64633620"
},
"2024-04-22": {
"1. open": "497.8300",
"2. high": "502.3800",
"3. low": "495.4300",
"4. close": "499.7200",
"5. volume": "67961048"
},
"2024-04-19": {
"1. open": "499.4400",
"2. high": "500.4550",
"3. low": "493.8600",
"4. close": "495.1600",
"5. volume": "102212587"
},
"2024-04-18": {
"1. open": "501.9800",
"2. high": "504.1300",
"3. low": "498.5600",
"4. close": "499.5200",
"5. volume": "74548085"
},
"2024-04-17": {
"1. open": "506.0500",
"2. high": "506.2200",
"3. low": "499.1200",
"4. close": "500.5500",
"5. volume": "75910305"
},
"2024-04-16": {
"1. open": "504.9400",
"2. high": "506.5000",
"3. low": "502.2100",
"4. close": "503.5300",
"5. volume": "73484020"
},
"2024-04-15": {
"1. open": "515.1300",
"2. high": "515.3000",
"3. low": "503.5800",
"4. close": "504.4500",
"5. volume": "92101447"
},
"2024-04-12": {
"1. open": "514.3700",
"2. high": "515.8150",
"3. low": "509.0800",
"4. close": "510.8500",
"5. volume": "92561094"
},
"2024-04-11": {
"1. open": "515.6800",
"2. high": "519.4800",
"3. low": "512.0800",
"4. close": "518.0000",
"5. volume": "70099007"
},
"2024-04-10": {
"1. open": "513.4800",
"2. high": "516.1600",
"3. low": "512.0900",
"4. close": "514.1200",
"5. volume": "82652806"
},
"2024-04-09": {
"1. open": "520.5000",
"2. high": "520.7500",
"3. low": "514.3500",
"4. close": "519.3200",
"5. volume": "67283576"
},
"2024-04-08": {
"1. open": "519.1500",
"2. high": "520.1800",
"3. low": "517.8900",
"4. close": "518.7200",
"5. volume": "47850048"
},
"2024-04-05": {
"1. open": "514.4600",
"2. high": "520.4400",
"3. low": "514.0100",
"4. close": "518.4300",
"5. volume": "73736571"
},
"2024-04-04": {
"1. open": "523.5200",
"2. high": "523.8674",
"3. low": "512.7550",
"4. close": "513.0700",
"5. volume": "95643401"
},
"2024-04-03": {
"1. open": "517.7200",
"2. high": "520.9500",
"3. low": "517.6650",
"4. close": "519.4100",
"5. volume": "58385823"
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment