// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © Bill_Howell // "$d_web"'CompLangs/PineScript/PuetzUWS SP500 multi-fractals 1826-2022.txt' //@version=5 indicator(title="PuetzUWS SP500 semiLog 1926-2022", shorttitle="PuetzUWS_SP500_1926_2022", overlay=true) // cannot do fractals with [hline, plot] - not accepted in local [function, for, if] // can use line.new [vertical, multiple of a base line, etc] // Don't use libraries!! it's too much of a mess... // 04Jun2022 I was finally able to publish the library but it doesn't seem to import? no action // https://www.tradingview.com/script/2OnKcFyO-HowellLibrary-time-labels/ //import Bill_Howell/HowellLibrary_time_labels/1 // Table of Contents : // Key [setup, parameters to adjust] // Setup - timeframe.period, n_bars, [min, max] of tracked main price series in chart // PriceFractals [Fibonacci, Liebnitz, Puetz] // Fibonnacci PriceFractals // Leibnitz PriceFractals (Gottfried Wilhelm Leibnitz), 19May2022 not coded yet (text pulled out) // Puetz PriceFractals (Stephen J. Puetz), 19May2022 not coded yet (text pulled out) // Plot PriceFractals // TimeFractals // Puetz TimeFractals (Stephen J. Puetz) - used for ALL [Fibonacci, Liebnitz, Puetz] timeFractals // as I know of no common timeFractals for [Fibonacci, Liebnitz] // however, the levels are different for each // plot Time Fractals (spikes or verticalLines) // Model of a series, 18May2022 not coded yet // WARNINGS! Pine Script coding // For [intro, concept, reference, TradingView's Pine Script language, [challenge, problem, debug]s] of this script, see : // http://www.BillHowell.ca/Software programming & code/PineScript for TradingView market charts/Howell - TradingView PineScript of priceTimeFractals.html // NOTE : "$d_webRawe" = http://www.BillHowell.ca // There is a great deal of [vestigial, anachronistic] code here, as I kept going back & forth to different // approaches to find solutions. Not entirely successfully... //+-----+ // Key [setup, parameters to adjust, general user-defined functions] // 19May2022 couldn't find input tabs, so normal Pine Script austment unavailable // input.string : // https://www.tradingcode.net/tradingview/pine-script-inputs/index.ccc548f771.html // nyet : fracTyp = input.string(title="fracTyp", options= ["Fibonacci", "Liebnitz", "Puetz"]) ) // nyet : var string fracTyp = array.new_string(9, "Fibonacci") var string fracTyp = "Fibonacci" // had to rip out to revert to old code, still want in future var float t_lagYears = 0.05 // shifts all time spikes // https://www.tradingview.com/pine-script-docs/en/v4/appendix/HOWTOs.html#count-bars-in-a-dataset // Find the highest and lowest values for the entire dataset // 20Mar2021 Howell - adapt this for viewable data biggest(series,size) => max = 0.0 for j = 0 to size if series[j] > max max := series[j] max smalest(series,size) => min = 100000. for j = size to 0 if series[j] < min min := series[j] min // Labels - // https://kodify.net/tradingview/bar-data/bar-number/ // How to get the bar number in TradingView Pine? (bar_index variable) // >> didn't work // https://kodify.net/tradingview/inputs/string-textbox-input/ // Creating a text box input option in TradingView Pine // stringVariable = input(title, type=string, defval, confirm) // 13May2022 write debug values to chart // 20May2022 I removed options xloc = xloc.bar_index, // initial version from a blog - I am getting "type-over" problem, but the lbl doesnt do anything // simple_label(bar_index,price,txt) => // var label lbl = na // label.delete(lbl) // lbl:=label.new(bar_index, price, txt, textcolor = color.black, color = na, style=label.style_label_left, size=size.large) simple_label(bar_index,price,txt) => label.new(bar_index, price, txt, textcolor = color.black, color = na, style=label.style_label_left, size=size.large) barLast_label(price,txt) => label.new(bar_index, price, txt, textcolor = color.black, color = na, style=label.style_label_left) // there is no first_bar_index -> just use 0 (zero) base // timeBarOffsets are backwards from a specified bar_index // priceOffsets are : + = upward; - = downward // PineScript reference : // Here, we store the 'last_bar_index' value that is known from the beginning of the script's calculation. // The 'last_bar_index' will change when new real-time bars appear, so we declare 'lastbar' with the 'var' keyword. // var lastbar = last_bar_index barFirst_label(n_bars, barOffset, serPrice, priceOffset, txt) => label.new(bar_index - n_bars + math.round(barOffset), serPrice + math.round(priceOffset), txt, textcolor = color.black, color = na, style=label.style_label_left) // 27May2022 didn't work // var firstBar = last_bar_index // barFirst_label(barOffset, serPrice, priceOffset, txt) => // label.new(firstBar + math.round(barOffset), serPrice + math.round(priceOffset), txt, textcolor = color.black, color = na, style=label.style_label_left) // time-based rather than bars time_label(timer, serPrice, priceOffset, txt) => label.new(timer, serPrice + math.round(priceOffset), txt, xloc = xloc.bar_time, textcolor = color.black, color = na, style=label.style_label_left) // time conversions var float year_to_minutes = 365.25*24*60 var float year_to_hours = 365.25*24 var float year_to_days = 365.25 var float year_to_weeks = 52.1786 var float year_to_months = 12.0 //+-----+ // Setup - timeframe.period, n_bars, [min, max] of tracked main price series in chart // User must turn OFF : SP500 axis menu -> Labels -> Indicators and financials name labels (no checkmark) // timeIdx = index to ary_t_length, the active chart timeSpan // t_lengthYear = duration of graph timescale for each timeperiod // visual = "1D" "5D" "1M" "3M" "6M" "1Y" "5Y" "All" // actual = 1 1 30 120 D W 30? or 20? //qnial> (1/365.25) (5/365.25) (1/12) (3/12) (1/2) (1.0) (5.0) (20) // .00273785 0.0136893 0.0833333 0.25 0.5 1. 5. 20. var int timeIdx = 0 // index to UWS constants if (timeframe.period == "1") timeIdx := 0 else if (timeframe.period == "5") timeIdx := 1 else if (timeframe.period == "30") timeIdx := 2 else if (timeframe.period == "60") timeIdx := 3 else if (timeframe.period == "120") timeIdx := 4 else if (timeframe.period == "D") timeIdx := 5 else if (timeframe.period == "W") timeIdx := 6 else if (timeframe.period == "M") timeIdx := 7 var ary_t_length = array.new_float(8, 0.0) init_t_length() => array.set(ary_t_length, 0, 0.00273785) array.set(ary_t_length, 1, 0.0136893) array.set(ary_t_length, 2, 0.0833333) array.set(ary_t_length, 3, 0.25) array.set(ary_t_length, 4, 0.5) array.set(ary_t_length, 5, 1.0) array.set(ary_t_length, 6, 5.0) array.set(ary_t_length, 7, 20.0) if barstate.isfirst init_t_length() // 20May2022 t_year_to_millisecs - convert t_lengthYear to millisecs (Unix time duration) var float t_year_to_millisecs = 365.25*24*60*60*1000 t_lengthYear = array.get(ary_t_length, timeIdx) // duration of graph timescale (years) t_lengthUnix = t_lengthYear * t_year_to_millisecs // duration of graph timescale (Unix millisecs) year_fraction = time / t_year_to_millisecs + 1970 var int t_start = 0 if barstate.isfirst t_start := time // n_bars = total number of bars shown in "viewable window", standard timeperiods only! // adapted from : // https://stackoverflow.com/questions/50087999/how-to-know-which-time-period-you-are-on-similar-to-isdaily-isweekly // how to know which time period you are on similar to isdaily, isweekly? // answered May 17 '18 at 6:07, Harold // https://www.tradingcode.net/tradingview/time-frame-period/ // Get a time frame’s period in TradingView with Pine Script // 15May2022 YIKES!!! timeframe.d is completely different than I expected // It's NOT the string-to-click that is seen at chart bottom (depends on series, I guess) // for SP500USD 6M=120 1Y=D 5Y=W All=M // 21May2022 WRONG approach!! user may elongate, shorten] timelines, for wich the presets won't work. I should use barstateis.[first, last] to calculate t_length[Bars, Time]. // n_bars = number of dataPoints on time axis // values for timeperiods = "1D" "5D" "1M" "3M" "6M" "1Y" "5Y" "All" (click text below chart) //qnial> (24*60*60) (24*60/5*12*7) (24*60*30) (24*30*3) (60/5*30*6) (30*12) (30*12*5) (30*12*50) //86400 24192. 43200 2160 2160. 360 1800 18000 // https://www.tradingview.com/pine-script-reference/#var_last_bar_index // last_bar_index - Bar index of the last chart bar. Bar indices begin at zero on the first bar. // ary_n_bar -> can cause scrunching of outputs!!! // 27May2022 PineScript provides no bug-free means of getting n_bars. // I did it by trial & error for each time periodand even then... // results aren't consistent even when I repeat the same thing with no code changes! // std TradingView timeScales ( 1D 5D 1M 3M 6M 1Y 5Y All) // last_bar_index (24924, 21257, 28294, 20055, 22804, 4951, 1000, 230) these vary a bit // ary_n_bars = array.from (24900, 21250, 28290, 20000, 22800, 4940, 1000, 230) // doesn't work at all // ary_n_bars = array.from ( 1440, 1440, 720, 2160, 2160, 240, 1800, 230) // scrunched a chart // ary_n_bars = array.from ( 720, 500, 500, 1500, 1500, 240, 240, 230) // 27May2022 best yet? still not good //ary_n_bars = array.from( 720, 500, 500, 1500, 800, 240, 240, 230) // 30May2022 better //ary_n_bars = array.from( 720, 500, 500, 1500, 600, 240, 240, 230) // 30May2022 bad // 30May2022 6M far better! bad : 1D, 5D ary_n_bars = array.from( 720, 500, 500, 1500, 1100, 240, 240, 230) var int n_bars = 2500 // number of datapoints on time axis n_bars := array.get(ary_n_bars, timeIdx) // 25May2022 use last_bar_index! -> doesn't work at lower timescales, I don't know why //n_last_bar_index = last_bar_index //n_bars := last_bar_index //if barstate.islast // simple_label(math.round(last_bar_index-200), close, "n_bars = " + str.tostring(n_bars)) // simple_label(math.round(last_bar_index-100), close, "last_bar_index = " + str.tostring(last_bar_index)) // Do not put in an if statement yet - needed by draw_spikes // Note : the y_axis may not be a price, it could be [volume, other], but the "price" term used here // 23May2022 do NOT declare with 'var'!!! : priceMin = smalest(close,n_bars) priceMax = biggest(close,n_bars) // 24************************24 // 24************************24 // Fibonacci priceFractals - are hard-bound to the SP500USD 1926-2020 semi-log trend line and // its standard deviation. (fib = number of relStdDev) // So they are tied to the SPXUSD over the last 83+ years, but are NOT related to current market specifics. // The Fibonacci series is mirrored [above, below] 1.000 : // * = non-primary-Fibonacci but often used (0.5, 0.78, 1.27, 2.0, also 0.65?) // 0.055728, 0.090170, 0.145898, 0.236072, 0.381971, 0.500000*, 0.618047, 0.786164*, 1.000000 // 17.94430, 11.09020, 6.854100, 4.236000, 2.618000, 2.000000*, 1.618000, 1.272000*, 1.000000 // calculate trendline calc_yTrend(x) => expnt = 0.792392+0.0289587*(x - 1926.25) // for 1871-1926 =10^( 0.784617 + (0.000140925*(x - 1871.08))) SP500base = math.pow(10,expnt) // The "relative standard deviation" (relStdDev or rsd) of the 83y trend is from the data 1926-2020 // see "$d_webRawe"'economics, markets/SP500/multi-fractal/SP500 1872-2020 TradingView, 1928-2020 yahoo // WARNING!!! This is probably wrong. Bese of code reversions, early mistakes in this scropting mini-project // keep coming back like zombies. examples : // fib0236Hi = (1 + 0.236*relStdDev/2) should be relStdDev (should be no "/2") // I don't trust this relStdDev = 0.4308 // 11May2022 adaptations y_base = calc_yTrend(year_fraction) ary_rsd = (close / y_base - 1) / relStdDev // 25May2022 probably WRONG!! - consider semi-log // fib = fibonacci levels [above, low] trend fib2618Hi = 2.618 fib2000Hi = 2.000 fib1618Hi = 1.618 fib1272Hi = 1.272 fib1000Hi = 1.000 fib0786Hi = 0.786 fib0618Hi = 0.618 fib0500Hi = 0.500 fib0382Hi = 0.382 fib0236Hi = 0.236 fib0000 = 1.000 fib0236Lo = 0.236 fib0382Lo = 0.382 fib0500Lo = 0.500 fib0618Lo = 0.618 fib0786Lo = 0.786 fib1000Lo = 1.000 fib1272Lo = 1.272 fib1618Lo = 1.618 fib2000Lo = 2.000 fib2618Lo = 2.618 // Fibonacci lines : lin2618Hi = (1 + relStdDev*fib2618Hi) * y_base lin2000Hi = (1 + relStdDev*fib2000Hi) * y_base lin1618Hi = (1 + relStdDev*fib1618Hi) * y_base lin1272Hi = (1 + relStdDev*fib1272Hi) * y_base lin1000Hi = (1 + relStdDev*fib1000Hi) * y_base lin0786Hi = (1 + relStdDev*fib0786Hi) * y_base lin0618Hi = (1 + relStdDev*fib0618Hi) * y_base lin0500Hi = (1 + relStdDev*fib0500Hi) * y_base lin0382Hi = (1 + relStdDev*fib0382Hi) * y_base lin0236Hi = (1 + relStdDev*fib0236Hi) * y_base lin0000 = (1 + relStdDev*fib0000 ) * y_base lin0236Lo = (1 + relStdDev*fib0236Lo) * y_base lin0382Lo = (1 + relStdDev*fib0382Lo) * y_base lin0500Lo = (1 + relStdDev*fib0500Lo) * y_base lin0618Lo = (1 + relStdDev*fib0618Lo) * y_base lin0786Lo = (1 + relStdDev*fib0786Lo) * y_base lin1000Lo = (1 + relStdDev*fib1000Lo) * y_base lin1272Lo = (1 + relStdDev*fib1272Lo) * y_base lin1618Lo = (1 + relStdDev*fib1618Lo) * y_base lin2000Lo = (1 + relStdDev*fib2000Lo) * y_base lin2618Lo = (1 + relStdDev*fib2618Lo) * y_base // rsd = relative standard deviation series, with respect to 1926-2020 SP500 semilog [trend, relStdDev] // no need to change : ary_rsd = (close / y_base - 1) / relStdDev var float rsd_min = 100000. var float rsd_max = -100000. rsd_min := smalest(ary_rsd, n_bars) rsd_max := biggest(ary_rsd, n_bars) // booleans - true if a fib level should be plotted (i.e. some point of it is between [min, max] values) bool2618Hi = rsd_min < fib2618Hi and fib2618Hi < rsd_max bool2000Hi = rsd_min < fib2000Hi and fib2000Hi < rsd_max bool1618Hi = rsd_min < fib1618Hi and fib1618Hi < rsd_max bool1272Hi = rsd_min < fib1272Hi and fib1272Hi < rsd_max bool1000Hi = rsd_min < fib1000Hi and fib1000Hi < rsd_max bool0786Hi = rsd_min < fib0786Hi and fib0786Hi < rsd_max bool0618Hi = rsd_min < fib0618Hi and fib0618Hi < rsd_max bool0500Hi = rsd_min < fib0500Hi and fib0500Hi < rsd_max bool0382Hi = rsd_min < fib0382Hi and fib0382Hi < rsd_max bool0236Hi = rsd_min < fib0236Hi and fib0236Hi < rsd_max bool0000 = rsd_min < fib0000 and fib0000 < rsd_max bool0236Lo = rsd_min < fib0236Lo and fib0236Lo < rsd_max bool0382Lo = rsd_min < fib0382Lo and fib0382Lo < rsd_max bool0500Lo = rsd_min < fib0500Lo and fib0500Lo < rsd_max bool0618Lo = rsd_min < fib0618Lo and fib0618Lo < rsd_max bool0786Lo = rsd_min < fib0786Lo and fib0786Lo < rsd_max bool1000Lo = rsd_min < fib1000Lo and fib1000Lo < rsd_max bool1272Lo = rsd_min < fib1272Lo and fib1272Lo < rsd_max bool1618Lo = rsd_min < fib1618Lo and fib1618Lo < rsd_max bool2000Lo = rsd_min < fib2000Lo and fib2000Lo < rsd_max bool2618Lo = rsd_min < fib2618Lo and fib2618Lo < rsd_max //+-----+ // plot Fibonacci mirror // note that the "plot" function cannot be a local : ie in [function, for, if, etc] plot(bool2618Hi ? lin2618Hi : na, color=color.gray, linewidth=1) plot(bool2000Hi ? lin2000Hi : na, color=color.gray, linewidth=1) plot(bool1618Hi ? lin1618Hi : na, color=color.gray, linewidth=1) plot(bool1272Hi ? lin1272Hi : na, color=color.gray, linewidth=1) plot(bool1000Hi ? lin1000Hi : na, color=color.gray, linewidth=1) plot(bool0786Hi ? lin0786Hi : na, color=color.gray, linewidth=1) plot(bool0618Hi ? lin0618Hi : na, color=color.gray, linewidth=1) plot(bool0500Hi ? lin0500Hi : na, color=color.gray, linewidth=1) plot(bool0382Hi ? lin0382Hi : na, color=color.gray, linewidth=1) plot(bool0236Hi ? lin0236Hi : na, color=color.gray, linewidth=1) plot(bool0000 ? lin0000 : na, color=color.navy, linewidth=3) plot(bool0236Lo ? lin0236Lo : na, color=color.gray, linewidth=1) plot(bool0382Lo ? lin0382Lo : na, color=color.gray, linewidth=1) plot(bool0500Lo ? lin0500Lo : na, color=color.gray, linewidth=1) plot(bool0618Lo ? lin0618Lo : na, color=color.gray, linewidth=1) plot(bool0786Lo ? lin0786Lo : na, color=color.gray, linewidth=1) plot(bool1000Lo ? lin1000Lo : na, color=color.gray, linewidth=1) plot(bool1272Lo ? lin1272Lo : na, color=color.gray, linewidth=1) plot(bool1618Lo ? lin1618Lo : na, color=color.gray, linewidth=1) plot(bool2000Lo ? lin2000Lo : na, color=color.gray, linewidth=1) plot(bool2618Lo ? lin2618Lo : na, color=color.gray, linewidth=1) if barstate.islast // simple_label(last_bar_index-200, close, "rsd_min = " + str.tostring(rsd_min)) // simple_label(last_bar_index-100, close, "rsd_max = " + str.tostring(rsd_max)) // Add Fibonacci mirror-labels barLast_label(bool2618Hi ? lin2618Hi : na, "+2.618") barLast_label(bool2000Hi ? lin2000Hi : na, "+2.000") barLast_label(bool1618Hi ? lin1618Hi : na, "+1.618") barLast_label(bool1272Hi ? lin1272Hi : na, "+1.272") barLast_label(bool1000Hi ? lin1000Hi : na, "+1.000") barLast_label(bool0786Hi ? lin0786Hi : na, "+0.786") barLast_label(bool0618Hi ? lin0618Hi : na, "+0.618") barLast_label(bool0500Hi ? lin0500Hi : na, "+0.500") barLast_label(bool0382Hi ? lin0382Hi : na, "+0.382") barLast_label(bool0236Hi ? lin0236Hi : na, "+0.236") barLast_label(bool0000 ? lin0000 : na, " 0.000") barLast_label(bool0236Lo ? lin0236Lo : na, "-0.236") barLast_label(bool0382Lo ? lin0382Lo : na, "-0.382") barLast_label(bool0500Lo ? lin0500Lo : na, "-0.500") barLast_label(bool0618Lo ? lin0618Lo : na, "-0.618") barLast_label(bool0786Lo ? lin0786Lo : na, "-0.786") barLast_label(bool1000Lo ? lin1000Lo : na, "-1.000") barLast_label(bool1272Lo ? lin1272Lo : na, "-1.272") barLast_label(bool1618Lo ? lin1618Lo : na, "-1.618") barLast_label(bool2000Lo ? lin2000Lo : na, "-2.000") barLast_label(bool2618Lo ? lin2618Lo : na, "-2.618") // Determine the highest "active" fibLine, for labelling chart var linHighest = lin2618Hi if bool2618Hi linHighest := lin2618Hi else if bool2000Hi linHighest := lin2000Hi else if bool1618Hi linHighest := lin1618Hi else if bool1272Hi linHighest := lin1272Hi else if bool1000Hi linHighest := lin1000Hi else if bool0786Hi linHighest := lin0786Hi else if bool0618Hi linHighest := lin0618Hi else if bool0500Hi linHighest := lin0500Hi else if bool0382Hi linHighest := lin0382Hi else if bool0236Hi linHighest := lin0236Hi else if bool0000 linHighest := lin0000 else if bool0236Lo linHighest := lin0236Lo else if bool0382Lo linHighest := lin0382Lo else if bool0500Lo linHighest := lin0500Lo else if bool0618Lo linHighest := lin0618Lo else if bool0786Lo linHighest := lin0786Lo else if bool1000Lo linHighest := lin1000Lo else if bool1272Lo linHighest := lin1272Lo else if bool1618Lo linHighest := lin1618Lo else if bool2000Lo linHighest := lin2000Lo else if bool2618Lo linHighest := lin2618Lo // 24************************24 // 24************************24 // TimeFractals //+-----+ // Puetz TimeFractals (Stephen J. Puetz) - used for ALL [Fibonacci, Liebnitz, Puetz] timeFractals // as I know of no common timeFractals for [Fibonacci, Liebnitz] // However, the levels are different for each // http://www.uct-news.com // 12May2022 initial // SP500 multi-fractal : 1926-2020 semi-log trend; Puetz "Universal Wave Series" temporal nested cycles // UWS wavelengths (cycle times in years) that I will use for the 1926-2020 SP500 semi-log trend are (rounded to 6 digits), but these NEED CORRECTION for trading hours etc (a project for the future - not likely for me). As TradingView typically plots trading days only, there won't be a good time-fit, especially for lower timescales. More sophisticated calculations could fix this, but that's for another day if ever. TradingView has "cyclic lines" to easily show temporal cycles on charts. // Fourier series analysis - might be a good starting spectral analysis to pick out relevant periods. // again, missing multiple n (HUWS) // While the ratios of UWS sequential periods are fixed to a factor of 3, the "anchor time" and perhaps more importantly the phase angles, depend on the application. // set UWS series parameters (not yet HUWS) // 16Mar2015 Howell adapted from "TradingView auto fib extension" standard PineScript library // 25May2022 oops still had erroneous "/2" : // 26May2022 these are NOT nested, as with the Puetz timeFractals below. // I couldn't get [line.new, nested [for, if] expressions] to work (see a previous section above) // lamda (cycle periods) // years months days hours // 1.072980E-04 0.940574 // 3.218942E-04 0.117572 2.82173 // 9.656826E-04 0.352716 8.46518 // 2.897047E-03 1.05815 25.3956 // 8.691143E-03 0.104294 3.17444 76.1866 // 2.607343E-02 0.312881 9.52332 228.56 // 7.822029E-02 0.938643 28.57 // 2.346608E-01 2.81593 85.7099 // 7.039826E-01 8.44779 257.13 // 2.111947E+00 25.3434 771.389 // 6.335843E+00 76.0301 // 1.900753E+01 228.09 // 5.702259E+01 // 1.710677E+02 // 5.132033E+02 // "anchor time" NYET -not used!! - just use the pure UWS times?? But how to adjust? // I will simply take the somewhat arbitrary date of the 1926 start of the SP500 series that I used : 1926.25. Fudging and excuses will follow later. Note that all UWS cycles align with the largest of the series, and hence with one another, so the choice of the start time is "universal" in a sense (but coud be wrong, obviously). UWS_lambda = array.from(0.0001072980, 0.0003218942, 0.0009656826, 0.002897047, 0.008691143, 0.02607343, 0.07822029, 0.2346608, 0.7039826, 2.111947, 6.335843, 19.00753, 57.02259, 171.0677, 513.2033) // phi angle (radians) - equivalent to lag times // these are simply fit to the data series // 13May2022 simple set phase angles to zero for initial coding. UWS_phi = array.from(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) // NOTE : as per the reference in section "" above, Puetz has recently used : // P(0,0) is a base cycle with a period of 2.82894367327307 solar years. // In comparison, above I have UWS[09] = 2.111947 years. But I do not have a complete updated table of USW [lambda, phi] to go by, so I simply used 2011 lambda rather than the 2014 numbers. // However, since the initial list of lamda in Puetz's 2011 book, the assigned values have been updated as many new time series have qualified for the Puetz UWS. Note that phi angles are specific to each application of each time series, and must be optimized for the problem at hand. 12May2022 THIS NEEDS TO BE UPDATED!! // Also not that the Half-UWS harmonics bring the UWS-HUWS cmbination much closer to a Fourier series! : // n is one of eight period-halving harmonics where n ∈ {0, 1, 2, 3, 4, 5, 6, 7} // Rather than show all of the above cycles on a graph, I will reduce the cycles according to the timescale of the chart : // find the UWS_lambda index of the largest ary_t_length fits into the chart timescale var int maxUWSLamdaIdx = 0 ary_t_length_biggest() => max = 0 for j = 0 to 14 if (array.get(UWS_lambda, j) < t_lengthYear) max := j max var lambda = array.new_float(5, 0.0) init_lambda() => for j = 0 to 4 array.set(lambda, j, array.get(UWS_lambda, maxUWSLamdaIdx - 2 + j)) var phi = array.new_float(5, 0.0) init_phi() => for j = 0 to 4 array.set(phi, 0, array.get(UWS_phi, maxUWSLamdaIdx - 2)) if barstate.isfirst maxUWSLamdaIdx := ary_t_length_biggest() init_lambda() init_phi() //+--+ // plot Time Fractal [spikes, label]s (spikes = verticalLines) // 12May2022 initial, 19May2022 generalized for [Fibonacci, Liebnitz, Puetz] // 19May2022 Half-UWS pike is NOT provided yet // inputs tab - cannot find anywhere for : // fracTyp = input.string(defval="Fibonacci", title="fracTyp", options= ["Fibonacci", "Liebnitz", "Puetz"]) // plot the UWS cycle times (not yet the HUWS) // code adapted from : // https://stackoverflow.com/questions/47610638/how-to-draw-a-vertical-line-in-tradingview-pine-script // How to draw a vertical line in TradingView pine script? // answered Jul 7, 2020 at 2:13, André // 13May2022 initial // t_baseUnix - when all UWS for this project assumed to coincide? (perhaps 1929 crash better assumption?) // should use Puetz time for coincidence of all UWS? (or some) - too broad? // t_lengthUnix - t_lengthYear coned to Unix (milliseconds) // iUWS - index for a reduced set of 5 UWS_lambda that will be marked // iUWS== 2 is max lambda that fits into t_lengthYear // actually, many more higher-level should be included! // flagSpike - boolean if any spikes occur over t_lengthYear for an iUWS // note that Puetz choose ?a few hundred miillion years ago? for one of his recent papers // t_mod - modulus (leftover) Unix time (milliseconds) from iUWS cycles starting from t_baseUnix // n_spikes - number of spikes for lamda(iUWS) showing over t_lengthYear // i_spike - index [0,..,4] of spike tbe displayed for lamda(iUWS) // offset - bars offset from timenow (barstate.islast) to placement of spike (towards barstate.isfirst) // timenow - PineScript Unix current time UTC wrt t_baseUnix // Current time in UNIX format. It is the number of milliseconds that have elapsed // since 00:00:00 UTC, 1 January 1970 // timestamp(year, month, day, hour, minute, second) → simple int // fom Setup (reminder) : // var float t_year_to_millisecs = 1000*60*60*24*365.25 var float t_shiftYears = 0.05 drawSpikes() => var bool flagSpike = true var int t_cycle = 0 var int t_mod = 0 var int t_spike = 0 var int n_spikes = 0 var int initSpike = 0 // skip daily chart, as SP500 [t_lengthUnix, n_bars] seem messed up // (maybe not available by minute or whatever) for iUWS = 0 to 4 flagSpike := true t_cycle := math.round(array.get(lambda, iUWS) * t_year_to_millisecs) t_mod := math.floor(((timenow / t_cycle) % 1) * t_cycle) // find last, closest] spike in t_lengthUnix if t_mod < t_lengthUnix t_spike := timenow - t_mod n_spikes := math.floor(((t_lengthUnix - t_mod) / t_cycle)) else if t_mod == 0.0 t_spike := timenow n_spikes := math.floor(((t_lengthUnix - t_mod) / t_cycle)) + 1 else if t_mod > t_lengthUnix flagSpike := false if flagSpike for i_spike = 0 to (n_spikes - 1) line.new(t_spike, priceMin, t_spike, priceMax, xloc = xloc.bar_time, color=color.black, width=iUWS + 1) // label each spike with its fractal depth# spikeSpaces = "" //time_label(t_spike, priceMax, 0, str.tostring(iUWS)) time_label(t_spike, priceMax, iUWS*40, str.tostring(iUWS)) t_spike := t_spike - t_cycle drawSpikes() // Create a legend showing periods for fractal depths if barstate.islast // test labels // barLast_label(price,txt) => //barLast_label(y_base, "Puetz timeFractal [depth, period]s") // barFirst_label(barFirstOffset, serPrice, priceOffset, txt) => //barFirst_label(0, y_base, 0, "Puetz timeFractal [depth, period]s") // simple_label(bar_index,price,txt) //simple_label(bar_index,close,"Puetz timeFractal [depth, period]s") // var float period = 0.0 var string periodLabel = "error" var float y_offset = 0.0 // timeBarOffsets are backwards from a specified bar_index // priceOffsets are : + = upward; - = downward // simple_label(last_bar_index-math.round(n_bars*2/3), y_base, "priceMin = " + str.tostring(priceMin)) // simple_label(last_bar_index-math.round(n_bars /2), y_base, "priceMax = " + str.tostring(priceMax)) // simple_label(last_bar_index-math.round(n_bars /4), y_base, "n_bars = " + str.tostring(n_bars)) //simple_label(last_bar_index-math.round(n_bars /4), y_base, "n_last_bar_index = " + str.tostring(n_last_bar_index)) // needs to be log? var string label="Puetz timeFractal [depth, period]s: " for iUWS = 0 to 4 period := array.get(lambda, iUWS) if period < 60/year_to_minutes period := period * year_to_minutes periodLabel := "minutes" else if period < 24/year_to_hours period := period * year_to_hours periodLabel := "hours" else if period < 7/year_to_days period := period * year_to_days periodLabel := "days" else if period < 4.1/year_to_weeks period := period * year_to_weeks periodLabel := "weeks" else if period < 1 period := period * year_to_months periodLabel := "months" else periodLabel := "years" label := label + str.tostring(period, '#.000') + " " + periodLabel + ", " //y_offset := y_legend - (iUWS + 1)*txtLineHeight txtLineHeight = (priceMax - priceMin)/6 y_offset := -1*txtLineHeight barFirst_label(n_bars, 100, priceMax, y_offset, label) // won't work : time_label(t_start, priceMax, y_offset, str.tostring(iUWS) + ". " + str.tostring(period, '#.000') + " " + periodLabel) //+-----+ // Model of a series, 18May2022 not coded yet // 12May2022 initial, 18May2022 not used yet (modelling of SP500 levels as Puetz does it - requires data fits) // Puetz seeks a model for market variables, notably indexes like SP5. However, that is not a current concern of mine. I am initially ONLY interested in the timing as per that last section. Coding maybe later... // Multiple "drivers" could share the same base period, but have different phase angles. This gets closer to Fourier Ses again? Can I use standard Fourier series analysis to derive a solid set of [lambda, phi], THEN use those efficent techniques to evolve a corresponding set of UWS[lambda, phi]. This would also greatly help to see if there is a significant difference between Puetz UWS and Fourier series. In other words, are they essentially the same for most practical systems, in that Puetz UWS pragmatically approximates a universal function approxmation capability. // Initially, I will ignore half-series and see how far that gets. Also - drop noise term // Original expressions : // P(k,n) = (3^k / 2^n) * P(0,0) // yi = sum[k=k1 to K: sum[n=n1 to N: A(k,n)*cos(2*π*(ti + φ) / P(k,n)) + σ*Zi ]] // become : // UWS_level(k) = 3^k * UWS_level(0) // yi = sum[k=k1 to K: sum[n=n1 to N: A(k,n)*cos(2*π*(ti + φ) / P(k)) ]] // UWS_weights depend on the application // 13May2022 for now juus all = 1.0 // UWSweight = array.new_float(15, 1.0) // UWS_signal - is a model for whichever market signal is being generated // 13May2022 just leave this for some e date when I get to the modelling phase // UWS_signal = array.new(n_bar, 1, 0) * n_bars / // again, missing multiple n for HUWS // UWS_signal(t) => // y = 0 // FOR t WITH 0 to n_bar // FOR n WITH 0 to 6 // y := y + array.get(UWS_weight, n)*cos(2*π*(t + array.get(phi, n) / array.get(lambda, n)) // ENDFOR // ENDFOR // endcode