Skip to content

Instantly share code, notes, and snippets.

@bjulius
Created June 18, 2023 08:17
Show Gist options
  • Save bjulius/145a196d4ac94b13b42461a0cfa7aff9 to your computer and use it in GitHub Desktop.
Save bjulius/145a196d4ac94b13b42461a0cfa7aff9 to your computer and use it in GitHub Desktop.
M and R Code for Dynamic Trend Stock Cards Using New Card Visual - Brian Julius
let
Source = Web.BrowserContents("https://finance.yahoo.com/quote/NVDA/history?p=NVDA"),
ExtractFromHTML = Html.Table(Source, {{"Column1", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}, {"Column2", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TH:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TD:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2) + TD[colspan=""6""]:not([rowspan]):nth-child(2):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}, {"Column3", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TH:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TH:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TD:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TD:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2) + TD[colspan=""6""]:not([rowspan]):nth-child(2):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}, {"Column4", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TH:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TH:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TH:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TD:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TD:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TD:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2) + TD[colspan=""6""]:not([rowspan]):nth-child(2):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}, {"Column5", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TH:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TH:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TH:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4) + TH:not([colspan]):not([rowspan]):nth-child(5):nth-last-child(3), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TD:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TD:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TD:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4) + TD:not([colspan]):not([rowspan]):nth-child(5):nth-last-child(3), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2) + TD[colspan=""6""]:not([rowspan]):nth-child(2):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}, {"Column6", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TH:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TH:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TH:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4) + TH:not([colspan]):not([rowspan]):nth-child(5):nth-last-child(3) + TH:not([colspan]):not([rowspan]):nth-child(6):nth-last-child(2), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TD:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TD:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TD:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4) + TD:not([colspan]):not([rowspan]):nth-child(5):nth-last-child(3) + TD:not([colspan]):not([rowspan]):nth-child(6):nth-last-child(2), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2) + TD[colspan=""6""]:not([rowspan]):nth-child(2):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}, {"Column7", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TH:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TH:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TH:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4) + TH:not([colspan]):not([rowspan]):nth-child(5):nth-last-child(3) + TH:not([colspan]):not([rowspan]):nth-child(6):nth-last-child(2) + TH:not([colspan]):not([rowspan]):nth-child(7):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TD:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TD:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TD:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4) + TD:not([colspan]):not([rowspan]):nth-child(5):nth-last-child(3) + TD:not([colspan]):not([rowspan]):nth-child(6):nth-last-child(2) + TD:not([colspan]):not([rowspan]):nth-child(7):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2) + TD[colspan=""6""]:not([rowspan]):nth-child(2):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}}, [RowSelector="TABLE.W\(100\%\).M\(0\) > * > TR"]),
Promote = Table.PromoteHeaders(ExtractFromHTML, [PromoteAllScalars=true]),
ReType = Table.TransformColumnTypes(Promote,{{"Date", type date}}),
RemoveErrors1 = Table.RemoveRowsWithErrors(ReType, {"Date"}),
UnpivotOther = Table.UnpivotOtherColumns(RemoveErrors1, {"Date"}, "Attribute", "Value"),
ReType2 = Table.TransformColumnTypes(UnpivotOther,{{"Value", Currency.Type}}),
RemovedErrors2 = Table.RemoveRowsWithErrors(ReType2, {"Value"}),
Filter = Table.SelectRows(RemovedErrors2, each ([Attribute] = "Adj Close**")),
Keep30 = Table.FirstN(Filter,30),
NVDAFinal = Table.ReplaceValue(Keep30,"**","",Replacer.ReplaceText,{"Attribute"}),
#"Removed Columns" = Table.RemoveColumns(NVDAFinal,{"Attribute"}),
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"Value", "AdjCloseNVDA"}}),
TGTSource = Web.BrowserContents("https://finance.yahoo.com/quote/TGT/history?p=TGT"),
TGTExtract = Html.Table(TGTSource, {{"Column1", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}, {"Column2", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TH:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TD:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2) + TD[colspan=""6""]:not([rowspan]):nth-child(2):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}, {"Column3", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TH:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TH:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TD:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TD:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2) + TD[colspan=""6""]:not([rowspan]):nth-child(2):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}, {"Column4", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TH:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TH:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TH:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TD:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TD:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TD:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2) + TD[colspan=""6""]:not([rowspan]):nth-child(2):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}, {"Column5", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TH:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TH:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TH:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4) + TH:not([colspan]):not([rowspan]):nth-child(5):nth-last-child(3), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TD:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TD:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TD:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4) + TD:not([colspan]):not([rowspan]):nth-child(5):nth-last-child(3), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2) + TD[colspan=""6""]:not([rowspan]):nth-child(2):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}, {"Column6", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TH:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TH:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TH:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4) + TH:not([colspan]):not([rowspan]):nth-child(5):nth-last-child(3) + TH:not([colspan]):not([rowspan]):nth-child(6):nth-last-child(2), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TD:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TD:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TD:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4) + TD:not([colspan]):not([rowspan]):nth-child(5):nth-last-child(3) + TD:not([colspan]):not([rowspan]):nth-child(6):nth-last-child(2), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2) + TD[colspan=""6""]:not([rowspan]):nth-child(2):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}, {"Column7", "TABLE.W\(100\%\).M\(0\) > * > TR > TH:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TH:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TH:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TH:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4) + TH:not([colspan]):not([rowspan]):nth-child(5):nth-last-child(3) + TH:not([colspan]):not([rowspan]):nth-child(6):nth-last-child(2) + TH:not([colspan]):not([rowspan]):nth-child(7):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(7) + TD:not([colspan]):not([rowspan]):nth-child(2):nth-last-child(6) + TD:not([colspan]):not([rowspan]):nth-child(3):nth-last-child(5) + TD:not([colspan]):not([rowspan]):nth-child(4):nth-last-child(4) + TD:not([colspan]):not([rowspan]):nth-child(5):nth-last-child(3) + TD:not([colspan]):not([rowspan]):nth-child(6):nth-last-child(2) + TD:not([colspan]):not([rowspan]):nth-child(7):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD:not([colspan]):not([rowspan]):nth-child(1):nth-last-child(2) + TD[colspan=""6""]:not([rowspan]):nth-child(2):nth-last-child(1), TABLE.W\(100\%\).M\(0\) > * > TR > TD[colspan=""7""]:not([rowspan]):nth-child(1):nth-last-child(1)"}}, [RowSelector="TABLE.W\(100\%\).M\(0\) > * > TR"]),
TGTPromote = Table.PromoteHeaders(TGTExtract, [PromoteAllScalars=true]),
TGT = Table.TransformColumnTypes(TGTPromote,{{"Date", type date}}),
TGTRemoveErrors1 = Table.RemoveRowsWithErrors(TGT, {"Date"}),
TGTUnpivotOther = Table.UnpivotOtherColumns(TGTRemoveErrors1, {"Date"}, "Attribute", "Value"),
TGTReType2 = Table.TransformColumnTypes(TGTUnpivotOther,{{"Value", Currency.Type}}),
TGTRemovedErrors2 = Table.RemoveRowsWithErrors(TGTReType2, {"Value"}),
TGTFilter = Table.SelectRows(TGTRemovedErrors2, each ([Attribute] = "Adj Close**")),
TGTKeep30 = Table.FirstN(TGTFilter,30),
TGTCleanHeaders = Table.ReplaceValue(TGTKeep30,"**","",Replacer.ReplaceText,{"Attribute"}),
TGTFinal = Table.RenameColumns(TGTCleanHeaders,{{"Value", "AdjCloseTGT"}}),
MergeQuotes = Table.Join(#"Renamed Columns", "Date", TGTFinal, "Date", JoinKind.Inner),
MaxDate = List.Max( MergeQuotes[Date]),
MinDate = Date.AddMonths( MaxDate , -1),
MaxDateHNum = Number.From( MaxDate ),
MinDateNum = Number.From( MinDate),
FullDateList = { MinDateNum..MaxDateHNum },
ToTable = Table.FromList(FullDateList, Splitter.SplitByNothing(), {"Date1"}, null, ExtraValues.Error),
DateTable = Table.TransformColumnTypes(ToTable,{{"Date1", type date}}),
Join = Table.Join(DateTable, "Date1", MergeQuotes, "Date", JoinKind.LeftOuter),
Sort = Table.Sort(Join,{{"Date1", Order.Ascending}}),
FillDown = Table.FillDown(Sort,{"AdjCloseNVDA", "AdjCloseTGT"}),
FIllUp = Table.FillUp(FillDown,{"AdjCloseNVDA", "AdjCloseTGT"}),
RemoveCols2 = Table.RemoveColumns(FIllUp,{"Date", "Attribute"}),
RenameDate = Table.RenameColumns(RemoveCols2,{{"Date1", "Date"}}),
SplitDate = Table.SplitColumn(Table.TransformColumnTypes(RenameDate, {{"Date", type text}}, "en-US"), "Date", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"Date.1", "Date.2", "Date.3"}),
AddDay = Table.AddColumn(SplitDate, "Day", each if Text.Length([Date.2]) =1 then "0" & [Date.2] else [Date.2]),
AddMonth = Table.AddColumn(AddDay, "Month", each if Text.Length([Date.1]) = 1 then "0" & [Date.1] else [Date.1]),
AssembleDate = Table.AddColumn(AddMonth, "Date", each [Date.3] &"-"& [Month] &"-"& [Day]),
FInalCleanup = Table.RemoveColumns(AssembleDate,{"Date.1", "Date.2", "Date.3", "Day", "Month"}),
#"Changed Type" = Table.TransformColumnTypes(FInalCleanup,{{"Date", type date}}),
AddDayOffset = Table.AddIndexColumn(#"Changed Type", "DayOffset", 1, 1, Int64.Type),
#"Changed Type1" = Table.TransformColumnTypes(AddDayOffset,{{"AdjCloseTGT", type number}, {"AdjCloseNVDA", type number}}),
#"Run R script" = R.Execute("library(readr)#(lf)library(zoo)#(lf)library(xts)#(lf)library(broom)#(lf)library(httr)#(lf)library(conflicted)#(lf)#(lf)conflict_prefer(""base::as.Date"", ""zoo::as.Date"")#(lf)#(lf)#(lf)api_key <- ""XXXXXXXXXXXXXXXXXXXXXXXXX""#(lf)Qdf <- dataset#(lf)#(lf)# Convert Date column to Date format#(lf)Qdf$Date <- as.Date(Qdf$Date, format = ""%m/%d/%Y %H:%M"")#(lf)#(lf)# Sort DayOffset variable in ascending order#(lf)sorted_order <- order(Qdf$DayOffset)#(lf)Qdf <- Qdf[sorted_order, ]# Create timeseries and trendline#(lf)tsNVDA <- zoo( Qdf$AdjCloseNVDA, order.by = Qdf$DayOffset )#(lf)lmNVDA <- lm(coredata(tsNVDA) ~ index(tsNVDA))#(lf)date <- index(tsNVDA)#(lf)NVDAcore <- coredata(tsNVDA)#(lf)NVDAtrend <- predict( lmNVDA )#(lf)#(lf)# Write trend coeffs to dataframe#(lf)CoeffsNVDA = tidy(lmNVDA)#(lf)#(lf)#(lf)# Plot ts and trend#(lf)plot(date, NVDAcore, type = ""l"", col = ""blue"", lwd = 3, xlab = """", ylab = """", main = ""NVDA 30 Day Trend"")#(lf)lines(date, NVDAtrend, lwd = 2, col = ""red"", lty = ""dotted"")#(lf)#(lf)# Write plot to PNG file#(lf)NVDAPng <- png(""NVDA.png"", width = 800, height = 600, bg = ""transparent"")#(lf)par(col.axis = ""white"")#(lf)plot(date, NVDAcore, type = ""l"", col = ""white"", lwd = 3, xlab = """", ylab = """", main = ""NVDA 30 Day Trend"", col.main = ""white"")#(lf)lines(date, NVDAtrend, lwd = 2, col = ""#02EEEE"", lty = ""dotted"")#(lf)dev.off()#(lf)#(lf)# Upload the PNG file to ImgBB#(lf)NVDAPost <- POST(#(lf) url = ""https://api.imgbb.com/1/upload"",#(lf) body = list(#(lf) ""key"" = api_key,#(lf) ""image"" = upload_file(""NVDA.png"", type = ""image/png"")#(lf) ),#(lf) encode = ""multipart""#(lf))#(lf)#(lf)#(lf)#(lf)# Create timeseries and trendline#(lf)tsTGT <- zoo( Qdf$AdjCloseTGT, order.by=Qdf$DayOffset)#(lf)lmTGT <- lm(coredata(tsTGT) ~ index(tsTGT))#(lf)date <- index(tsTGT)#(lf)TGTcore <- coredata(tsTGT)#(lf)TGTtrend <- predict( lmTGT )#(lf)#(lf)# Write trend coeffs to dataframe#(lf)CoeffsTGT = tidy(lmTGT)#(lf)#(lf)#(lf)# Plot ts and trend#(lf)plot(date, TGTcore, type = ""l"", col = ""blue"", lwd = 3, xlab = """", ylab = """", main = ""TGT 30 Day Trend"")#(lf)lines(date, TGTtrend, lwd = 2, col = ""red"", lty = ""dotted"")#(lf)#(lf)# Write plot to PNG file#(lf)TGTPng <- png(""TGT.png"", width = 800, height = 600, bg = ""transparent"")#(lf)par(col.axis = ""white"")#(lf)plot(date, TGTcore, type = ""l"", col = ""white"", lwd = 3, xlab = """", ylab = """", main = ""TGT 30 Day Trend"", col.main = ""white"")#(lf)lines(date, TGTtrend, lwd = 2, col = ""#02EEEE"", lty = ""dotted"")#(lf)dev.off()#(lf)#(lf)# Upload the PNG file to ImgBB#(lf)TGTPost <- POST(#(lf) url = ""https://api.imgbb.com/1/upload"",#(lf) body = list(#(lf) ""key"" = api_key,#(lf) ""image"" = upload_file(""TGT.png"", type = ""image/png"")#(lf) ),#(lf) encode = ""multipart""#(lf))",[dataset=#"Changed Type1"]),
#"Expanded Value" = Table.ExpandTableColumn(#"Run R script", "Value", {"term", "estimate", "std.error", "statistic", "p.value", "AdjCloseNVDA", "AdjCloseTGT", "Date", "DayOffset"}, {"term", "estimate", "std.error", "statistic", "p.value", "AdjCloseNVDA", "AdjCloseTGT", "Date", "DayOffset"})
in
#"Expanded Value"
@bjulius
Copy link
Author

bjulius commented Jun 18, 2023

When you embed R: code within M code, the R code is formatted in a pretty unreadable manner, so here's a better formatted version of the R script called above within Power Query to do the time series trend analysis, create the PNG graphics, and automatically upload them to the ImgBB API:

library(readr)
library(zoo)
library(xts)
library(broom)
library(httr)
library(conflicted)

conflict_prefer("base::as.Date", "zoo::as.Date")

NOTE: sub your API key in for the Xs

api_key <- "XXXXXXXXXXXXXXXXXXXXX"
Qdf <- dataset

Convert Date column to Date format

Qdf$Date <- as.Date(Qdf$Date, format = "%m/%d/%Y %H:%M")

Sort DayOffset variable in ascending order

sorted_order <- order(Qdf$DayOffset)
Qdf <- Qdf[sorted_order, ]# Create timeseries and trendline
tsNVDA <- zoo( Qdf$AdjCloseNVDA, order.by = Qdf$Date )
lmNVDA <- lm(coredata(tsNVDA) ~ index(tsNVDA))
date <- index(tsNVDA)
NVDAcore <- coredata(tsNVDA)
NVDAtrend <- predict( lmNVDA )

Write trend coeffs to dataframe

CoeffsNVDA = tidy(lmNVDA)

Plot ts and trend

plot(date, NVDAcore, type = "l", col = "blue", lwd = 3, xlab = "", ylab = "", main = "NVDA 30 Day Trend")
lines(date, NVDAtrend, lwd = 2, col = "red", lty = "dotted")

Write plot to PNG file

NVDAPng <- png("NVDA.png", width = 800, height = 600, bg = "transparent")
par(col.axis = "white")
plot(date, NVDAcore, type = "l", col = "white", lwd = 3, xlab = "", ylab = "", main = "NVDA 30 Day Trend", col.main = "white")
lines(date, NVDAtrend, lwd = 2, col = "#02EEEE", lty = "dotted")
dev.off()

Upload the PNG file to ImgBB

NVDAPost <- POST(
url = "https://api.imgbb.com/1/upload",
body = list(
"key" = api_key,
"image" = upload_file("NVDA.png", type = "image/png")
),
encode = "multipart"
)

Create timeseries and trendline

tsTGT <- zoo( Qdf$AdjCloseTGT, order.by=Qdf$DayOffset)
lmTGT <- lm(coredata(tsTGT) ~ index(tsTGT))
date <- index(tsTGT)
TGTcore <- coredata(tsTGT)
TGTtrend <- predict( lmTGT )

Write trend coeffs to dataframe

CoeffsTGT = tidy(lmTGT)

Plot ts and trend

plot(date, TGTcore, type = "l", col = "blue", lwd = 3, xlab = "", ylab = "", main = "TGT 30 Day Trend")
lines(date, TGTtrend, lwd = 2, col = "red", lty = "dotted")

Write plot to PNG file

TGTPng <- png("TGT.png", width = 800, height = 600, bg = "transparent")
par(col.axis = "white")
plot(date, TGTcore, type = "l", col = "white", lwd = 3, xlab = "", ylab = "", main = "TGT 30 Day Trend", col.main = "white")
lines(date, TGTtrend, lwd = 2, col = "#02EEEE", lty = "dotted")
dev.off()

Upload the PNG file to ImgBB

TGTPost <- POST(
url = "https://api.imgbb.com/1/upload",
body = list(
"key" = api_key,
"image" = upload_file("TGT.png", type = "image/png")
),
encode = "multipart"
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment