// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © Bill_Howell //@version=5 indicator(title="PuetzUWS [time, price] multiFractals (version 2), Intl Stock Indexes", shorttitle="PuetzUWS IntlStkIdxs multi-fractals (version 2)", overlay=true) // 24************************24 // Table of Contents : // Quick notes // Descriptions of [constant, function] symbols used in this PineScript // Key [setup, parameters to adjust] // Setup - timeframe.period, n_bars, [min, max] of tracked main price series in chart // Symbols' pricing semi-log {[trend, relStdDev], priceRsd[Min, Max, Spread]Idx} // 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) // 24************************24 // 24************************24 // Quick notes // For [intro, concept, reference, TradingView's Pine Script language, [challenge, problem, debug]s] of this script, webSearch my name and this script? // Make sure that the overlay output "PeutzUWS 1872-2020 fractal mirrors" is on a separate axis! // right click on detrended SPX, select "pin to new right scale" // Select "seetings for each axis (except TVC: TNX 10yT-bond rate) and select "logaritmic" // 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... // 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 // 24************************24 // Descriptions of [constant, function] symbols used in this PineScript // priceFractal | timeFractal // ---------------|--------------- // flagSpike | flagSpike boolean -whether to output a [line, spike] // lambdaPuetzUWS | lambdaPuetzUWS PuetzUWS (Universal Wave Series), period = cycle lengths (years) // rsdPuetzUWS | timeLambda PuetzUWS converted to relStdDev [time, price] // midIdx | n/a [PuetzUWS, rsdPuetzUWS] index, such that rsdPuetzUWS = 1.000 // p_cycle | t_cycle current cycle length in [drawPriceFrac, drawTimeFrac] // priceRsdMax? | t_now . // priceRsdMax? | timenow . // p_mod | t_mod modulus (leftover) iUWS p_cycles from basLevel to rsdLevel // priceRsdCum | t_spike . // n_spikes | n_spikes number of iUWS [line, spike]s to show on chart // n/a | t_lengthUnix chart's time duration (t_lengthYear) converted to Unix (milliseconds) // n/a | timenow Unix current time UTC (milliseconds since 01Jan1970) // n_bars | ?can't get starting [bar, time], - sloppy guess // y_offset | y_offset price offset, typically from a [line, spike] on chart, for labels // 24************************24 // Basic [constant, function]s used in rest of library // lambdaPuetzUWS - used for timeFractals, all of which are positive! lambdaPuetzUWS = 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) // rsdPuetzUWS - used for priceFractals, which are both [posit, negat]ive! // rsdPuetzUWS = lambdaPuetzUWS / 0.2346608 (mid-range value) // full sequence reversal // this shorter rsdPuetzUWS sequence - will NOT accomodate cypto and other extremely high growth! nor negatives rsdPuetzUWS = array.from(-9., -3., -1., -0.333333, -0.111111, -0.037037, -0.0123457, -0.00411523, -0.00137174, -0.000457247, 0.000, 0.000457247, 0.00137174, 0.00411523, 0.0123457, 0.037037, 0.111111, 0.333333, 1., 3., 9.) // 21 elements, (0 - 20) midIdx == 10 lastRsdIdx = array.size(rsdPuetzUWS) - 1 midIdx = math.floor(array.size(rsdPuetzUWS) / 2) // 09Jun2022 not used yet : string fracTyp = "Fibonacci" // had to rip out to revert to old code, still want in future float t_lagYears = 0.05 // shifts all time spikes // Find the highest and lowest values for the entire dataset // 20Mar2021 Howell - adapt this for viewable data // 11Jun2022 old approach very inefficient, don't use these normally! 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 = 0 to size if series[j] < min min := series[j] min // 24************************24 // Time - timeframe.period, n_bars, [min, max] of tracked main price series in chart (once stable, generalised) // 03Jun2022 Much of this should go into a library to use across my PineScript code (once stable, generalised) // but I couldn't get a library to work // User must turn OFF : SP500 axis menu -> Labels -> Indicators and financials name labels (no checkmark) // time conversions var float t_year_to_millisecs = 365.25*24*60*60*1000 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 // timeIdx = index to ary_t_length, the active chart timeSpan // visual = "1D" "5D" "1M" "3M" "6M" "1Y" "5Y" "All" "All 01Feb1871" // actual = 1 1 30 120 D W 30? or 20? 20? //qnial> (1/365.25) (5/365.25) (1/12) (3/12) (1/2) (1.0) (5.0) (20) (20) // .00273785 0.0136893 0.0833333 0.25 0.5 1. 5. 20. 150. // set to true to go back to 01Feb1871 flag_1871 = true 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") and flag_1871 timeIdx := 8 else if (timeframe.period == "M") timeIdx := 7 // does "1" n_bars (1 hour timeframe.period 1 day t_length) change over course of day? // t_lengthYear = duration of graph timescale for each timeperiod // 1Jun2022 this did NOT work when declared as t_lenghtYear = 0.0, then // t_lengthYear := array.get(ary_t_length, timeIdx) Whyy!!!? very frustrating!!! ary_t_length = array.from(0.00273785, 0.0136893, 0.0833333, 0.25, 0.5, 1.0, 5.0, 20.0, 150.0) // declaring these as float, or "var float" won't work???!!!??? t_lengthYear = array.get(ary_t_length, timeIdx) // duration of graph timescale (years) t_lengthUnix = math.floor(t_lengthYear * t_year_to_millisecs) // duration of graph timescale (milliseconds) year_fraction = time / t_year_to_millisecs + 1970 // strange shift 01Mar1922 to 01Aug1929 t_unix01Jan1970_to_unix01Jul1929(t_unix01Jan1970) => math.floor(t_unix01Jan1970 + (1929.5833 - 7.25)*t_year_to_millisecs) // ary_n_bar -> can cause scrunching of outputs!!! very finicky to set - wish I had a robust n_bars, t_start! // 27May2022 PineScript provides no bug-free means of getting n_bars. // see '0_PineScript notes.txt' : // I did it by trial & error for each time period and even then... // std TradingView timeScales ( 1D 5D 1M 3M 6M 1Y 5Y All "All, 01Feb1871") // last_bar_index (24924 21257 28294 20055 22804 4951 1000 230 ????) these vary a bit ary_n_bars = array.new(8, 0) //ary_n_bars := array.from( 1300 1300 1100 1500 1500 240 240 250 1500) // 15Jun2022 ary_n_bars := array.from( 600, 350, 400, 600, 1500, 240, 240, 250, 1500) // 20Jun2022 // 20Jun2022 using last_bar_index (number of datapoints on time axis) DOESN'T work! // Study Error : This study references too many candles in history (eg 5001) //n_bars = last_bar_index n_bars = array.get(ary_n_bars, timeIdx) bar_9_10th = last_bar_index - math.round(n_bars*0.9) bar_2_3rds = last_bar_index - math.round(n_bars*2/3) bar_1_half = last_bar_index - math.round(n_bars /2) bar_3_8ths = last_bar_index - math.round(n_bars*3/8) bar_1_qrtr = last_bar_index - math.round(n_bars /4) bar_1_8ths = last_bar_index - math.round(n_bars /8) bar_zeroth = last_bar_index // 20Jun2022 couldn't get these to work - problems with : // Study Error : This study references too many candles in history (eg 5001) barFraction_to_barIndex(barFraction) => last_bar_index * (1.0 - barFraction) barFraction_to_yFraction(barFraction) => (last_bar_time / t_year_to_millisecs) - ((t_lengthUnix * barFraction) / t_year_to_millisecs) + 1970 // 24************************24 // Labels // 03Jun2022 Much of this should go into a library to use across my PineScript code (once stable, generalised) // but I couldn't get a library to work simple_label(int bar_index, float price, string txt) => label.new(bar_index, price, txt, textcolor = color.black, color = na, style=label.style_label_left, size=size.large) barLast_label(float price, string txt) => label.new(bar_index, price, txt, textcolor = color.black, color = na, style=label.style_label_left) // priceOffsets are : + = upward; - = downward barFirst_label(float barFractionFrmRight, float serPrice, float priceOffset, string txt) => label.new(last_bar_index-math.round(n_bars*barFractionFrmRight), serPrice + priceOffset, txt, textcolor = color.black, color = na, style=label.style_label_left) // 03Jun2022 new "table" functions are not very good yet! // better this simple approach mat_write(string matTitle, matrix matSymbol, int n_bars, int barRightShift, float serPrice, float txtLineHeight) => rows = matrix.rows(matSymbol) cols = matrix.columns(matSymbol) rowStr = "" num = 10.0 y_offset = 0.0 y_offset := -6*txtLineHeight // barFirst_label(float barFractionFrmRight, float serPrice, float priceOffset, string txt) => barFirst_label(0.75, serPrice, y_offset, matTitle) for iRow = 0 to (rows - 1) rowStr := "" for iCol = 0 to (cols - 1) num := matrix.get(matSymbol, iRow, iCol) rowStr := rowStr + str.tostring(num, '#.000') + " " y_offset := float(-(iRow + 7)*txtLineHeight) barFirst_label(0.75, serPrice, y_offset, rowStr) // 24************************24 // price[Min, Max] over full length of t_timelength, txtLineHeight // 23May2022 do NOT declare with 'var'!!! : priceMin = smalest(close, n_bars) priceMax = biggest(close, n_bars) // 24************************24 // 24************************24 // Symbols' pricing semi-log {[trend, relStdDev], priceRsd[Min, Max, Spread]Idx, etc} // refer to my webSite (good luck with the webSearch) for details // Wilhelm Abel ?1937?, David Fischer 1996, I've used the following split : // price equilibrium (stable prices) 1871-1926 // price revolution 1926-2020 // 11Aug2022 QNial work may sho that the breakover should be in the 1950's? (maybe Breton Woods 1944?) // calculate priceRsds for a semiLog detrended symbol using regression parameters // over a "segment" of time for symbols with multiple segments priceNormal_regressParams_to_priceNormalRsd(price, constant, slope, relStdDev, yrStrtRegr) => priceNormalTrend = constant + slope * (year_fraction - yrStrtRegr) (price / priceNormalTrend - 1) / relStdDev priceNormal_regressParams_to_priceSemilogRsd(price, constant, slope, relStdDev, yrStrtRegr) => priceLogTrend = constant + slope * (year_fraction - yrStrtRegr) (math.log(price) / priceLogTrend - 1) / relStdDev // SPX "zero level" priceRsds - [1926.25-2020.???, 1872-1926.25] // too lazy to get 2020 exact endDate of regression fit // rather than feed a jillion parameters to a function, easier to do special func // special funcs also good for [multiple segments, strange conditions, etc] calc_SP500Trend() => relStdDev = 0.4308 if year_fraction <= 1926.25 relStdDev := 0.3314 expnt = 0.0 if year_fraction >= 1926.25 expnt := 0.792392+0.0289587*(year_fraction - 1926.25) else expnt := 0.784617+1.40925E-04 *(year_fraction - 1871.08) SP500base = math.pow(10,expnt) lin0000 = calc_SP500Trend() // lin0000_[start, end] : don't need, its just lin0000 at barstate.islast (horizontal lines) priceRsd = priceNormal_regressParams_to_priceSemilogRsd(close) plot(priceRsd, color=color.aqua, linewidth=2) // 20Jun2022 using lin0000[barIndex] DOESN'T work! // Study Error : This study references too many candles in history (eg 5001) priceRsd_to_priceNormal(rsd) => relStdDev = 0.4308 if year_fraction <= 1926.25 relStdDev := 0.3314 lin0000 * (rsd * relStdDev + 1) // priceNormal = priceRsd_to_priceNormal(priceRsd) // Non-SP500 symbols - detrended priceRsds, as per function defn above // symbol_detrend := priceNormal_regressParams_to_price[Normal, Semilog]Rsd // (symbol, constant, slope, relStdDev, yrStrtRegr) DAX40 = request.security("TVC:UKX", timeframe.period, close) DAX40_detrend = 0. DAX40_detrend := priceNormal_regressParams_to_priceSemilogRsd(DAX40, (TNX, -61.6481, 0.0325753, 0.0351671, 1970.) plot(DAX_detrend, color=color.orange, title="DAX40 Germany stkIdx") // HSSSHSC300 = request.security("HSI:HSSSHSC", timeframe.period, close) // HSSSHSC300_detrend = 0. // HSSSHSC300_detrend := priceNormal_regressParams_to_priceSemilogRsd(HSSSHSC300, constant, slope, relStdDev, yrStrtRegr) // plot(HSSSHSC300_detrend, color=color.orange, title="HSSSHSC300 China Shanghai-Shenzen-Hong Kong stkIdx") INDIA50 = request.security("Vantage:INDIA50", timeframe.period, close) INDIA50_detrend = 0. INDIA50_detrend := priceNormal_regressParams_to_priceSemilogRsd(INDIA50, -96.3589, 0.0497382, 0.00785659, 2013.16) plot(INDIA50_detrend, color=color.orange, title="INDIA50 nifty fifty stkIdx") NI225 = request.security("TVC:NI225", timeframe.period, close) NI225_detrend = 0. NI225_detrend := priceNormal_regressParams_to_priceSemilogRsd(NI225, -1.66838 0.00291729 0.0341034 1992.33) plot(NI2250_detrend, color=color.orange, title="NI225 Japan stkIdx") SPX500 = request.security("TVC:SPX", timeframe.period, close) SPX500Lo_detrend = 0. SPX500Hi_detrend = 0. IF year_fraction <= 1940.06 SPX500Lo_detrend := priceNormal_regressParams_to_priceSemilogRsd(SPX, -14.9701 0.00830613 0.122382 1871.22) IF year_fraction >= 1926.06 SPX500Hi_detrend := priceNormal_regressParams_to_priceSemilogRsd(SPX, -56.7736 0.0298315 0.0937853 1926.06) plot(SPX500Lo_detrend, color=color.orange, title="SPX500 USA stkIdx 1871-1940") plot(SPX500Hi_detrend, color=color.orange, title="SPX500 USA stkIdx 1926-2022") // SP500base = math.pow(10,expnt) SPX500_detrend := priceNormal_regressParams_to_priceSemilogRsd(SPX, -1.66838 0.00291729 0.0341034 1992.33) // DON'T take log of interest rates! but invert them with respect to stock indexes TNX = request.security("TVC:TNX", timeframe.period, close) TNX_detrend = 0. TNX_detrend := priceNormal_regressParams_to_priceNormalRsd(TNX, -61.6481, 0.0325753, 0.0351671, 1970.) plot(TNX_detrend, color=color.orange, title="TNX 10yr T-bond USA") UKX100 = request.security("TVC:UKX", timeframe.period, close) UKX100_detrend = 0. UKX100_detrend := priceNormal_regressParams_to_priceSemilogRsd(UKX100, constant, slope, relStdDev, yrStrtRegr) plot(UKX_detrend, color=color.orange, title="UKX100 long term stkIdx") // 24************************24 // 24************************24 // [Puetz, 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. // [lambdaPuetzUWS, rsdPuetzUWS] defined in setup section above // note that the "plot" function cannot be a local : ie in [function, for, if, etc] // for price, key fractal measure is rsdPrice, preferably with 1.0 in set rsdPuetzUWS? // wanted to have options on type of priceFractals : Puetz framework, Fibonacci lowest level? // priceRsd[Min, Max] over full length of t_timelength float priceRsdMin = 10.0 float priceRsdMax = -10.0 priceRsdMin := smalest(priceRsd, n_bars) priceRsdMax := biggest(priceRsd, n_bars) priceRsdMin_to_lambdaIdx() => idxMin = 0 for j = 0 to lastRsdIdx if array.get(rsdPuetzUWS, j) < priceRsdMin idxMin := j idxMin priceRsdMax_to_lambdaIdx() => idxMax = 0 for j = lastRsdIdx to 0 if array.get(rsdPuetzUWS, j) > priceRsdMax idxMax := j idxMax // priceRsd[Min, Max, Bas] to indexs float priceRsdBas = 0.0 int priceRsdMinIdx = 0 int priceRsdMaxIdx = 0 int priceRsdBasIdx = 0 int priceRsdLesIdx = 0 int priceRsdBelowIdx = midIdx int priceRsdAboveIdx = midIdx int priceRsdBelowStopIdx = midIdx int priceRsdAboveStopIdx = midIdx float txtLineHeight = 0.0 if barstate.islast txtLineHeight := (priceRsdMax - priceRsdMin)/10 // priceRsdMinIdx, := priceRsdMin_to_lambdaIdx() priceRsdMaxIdx, := priceRsdMax_to_lambdaIdx() // // set iUWS ranges to provide common fractal levels [below, above] rsd = 1.000 if priceRsdMinIdx <= midIdx and priceRsdMaxIdx <= midIdx priceRsdBelowIdx := priceRsdMinIdx priceRsdBelowStopIdx := priceRsdBelowIdx + 2 if priceRsdBelowStopIdx > midIdx priceRsdBelowStopIdx := midIdx else if priceRsdMinIdx >= midIdx and priceRsdMaxIdx >= midIdx priceRsdAboveIdx := priceRsdMaxIdx priceRsdAboveStopIdx := priceRsdAboveIdx - 2 if priceRsdAboveStopIdx < midIdx priceRsdAboveStopIdx := midIdx else // adjust +1 because off midIdx if math.abs(priceRsdMinIdx - midIdx) > math.abs(priceRsdMaxIdx - midIdx) priceRsdBasIdx := math.abs(priceRsdMinIdx - midIdx) - 1 else priceRsdBasIdx := math.abs(priceRsdMaxIdx - midIdx) - 1 // if priceRsdBasIdx < 2 priceRsdLesIdx := midIdx else priceRsdLesIdx := priceRsdBasIdx - 2 // priceRsdBelowIdx := midIdx - priceRsdBasIdx priceRsdAboveIdx := midIdx + priceRsdBasIdx priceRsdBelowStopIdx := midIdx - priceRsdLesIdx priceRsdAboveStopIdx := midIdx + priceRsdLesIdx // Bug check - output variables on chart simple_label_prices() => float priceLabel = 0.0 // bar_[2_3rds, 1_half, 1_qrtr] are defined above in section "Time - timeframe.period, n_bars, [min, max]" // priceLabel := priceRsdMax - 2*txtLineHeight simple_label(bar_2_3rds, priceLabel, "priceMin = " + str.tostring(priceMin)) simple_label(bar_1_half, priceLabel, "priceMax = " + str.tostring(priceMax)) simple_label(bar_1_qrtr, priceLabel, "midIdx = " + str.tostring(midIdx)) // priceLabel := priceRsdMax - 3*txtLineHeight simple_label(bar_2_3rds, priceLabel, "priceRsdMin = " + str.tostring(priceRsdMin, '#.000')) simple_label(bar_1_half, priceLabel, "priceRsdMax = " + str.tostring(priceRsdMax, '#.000')) simple_label(bar_1_qrtr, priceLabel, "lastRsdIdx = " + str.tostring(lastRsdIdx)) // priceLabel := priceRsdMax - 4*txtLineHeight simple_label(bar_2_3rds, priceLabel, "priceRsdMinIdx = " + str.tostring(priceRsdMinIdx)) simple_label(bar_1_half, priceLabel, "priceRsdMaxIdx = " + str.tostring(priceRsdMaxIdx)) simple_label(bar_1_qrtr, priceLabel, "priceRsdBasIdx = " + str.tostring(priceRsdBasIdx)) // priceLabel := priceRsdMax - 5*txtLineHeight simple_label(bar_2_3rds, priceLabel, "priceRsdBelowIdx = " + str.tostring(priceRsdBelowIdx)) simple_label(bar_1_half, priceLabel, "priceRsdBelowStopIdx = " + str.tostring(priceRsdBelowStopIdx)) // priceLabel := priceRsdMax - 6*txtLineHeight simple_label(bar_2_3rds, priceLabel, "priceRsdAboveStopIdx = " + str.tostring(priceRsdAboveStopIdx)) simple_label(bar_1_half, priceLabel, "priceRsdAboveIdx = " + str.tostring(priceRsdAboveIdx)) // simple_label(bar_1_qrtr, priceRsdMin, "n_bars = " + str.tostring(n_bars)) //if barstate.islast // simple_label_prices() if barstate.islast priceLabel = priceRsdMax - 1*txtLineHeight simple_label(bar_2_3rds, priceLabel, "timeframe.period = " + timeframe.period) // drawPriceFrac() - for now only nests 2 levels below topLevel // 08Jun2022 need to do [above, below] lin0000 (fractal = 1.000) - currently just above drawPriceFrac() => bool flagSpike = true int iStop = 0 int widthr = 1 float y_offset = 0.0 float priceRsdBelow = 0.0 float priceRsdAbove = 0.0 float priceRsdBelowStop = 0.0 float priceRsdAboveStop = 0.0 float priceRsdNow = 0.0 float priceRsdStep = 0.0 float priceLabel = 0.0 // // do levels below priceRsd = 1.000, if they are present if priceRsdMin < 0.000 iStop := 0 widthr := 0 priceRsdBelow := array.get(rsdPuetzUWS, priceRsdBelowIdx) priceRsdBelowStop := array.get(rsdPuetzUWS, priceRsdBelowStopIdx) //priceLabel := priceRsdMax - 7*txtLineHeight //simple_label(bar_2_3rds, priceLabel, "priceRsdBelowStop = " + str.tostring(priceRsdBelowStop)) //simple_label(bar_1_half, priceLabel, "priceRsdBelow = " + str.tostring(priceRsdBelow)) for iRSD = priceRsdBelowStopIdx to priceRsdBelowIdx widthr := widthr + 1 priceRsdStep := array.get(rsdPuetzUWS, iRSD) priceRsdNow := 0.0 while (priceRsdMin <= priceRsdNow) and (iStop < 300) if priceRsdNow <= priceRsdMax line.new(last_bar_index - n_bars, priceRsdNow, last_bar_index, priceRsdNow, color=color.black, width=widthr) barLast_label(priceRsdNow, " " + str.tostring(priceRsd_to_priceNormal(priceRsdNow), '#')) priceRsdNow := priceRsdNow + priceRsdStep iStop := iStop + 1 // // do levels above priceRsd = 1.000, if they are present if priceRsdMax >= 0.000 iStop := 0 widthr := 0 priceRsdAbove := array.get(rsdPuetzUWS, priceRsdAboveIdx) priceRsdAboveStop := array.get(rsdPuetzUWS, priceRsdAboveStopIdx) //priceLabel := priceRsdMax - 8*txtLineHeight //simple_label(bar_2_3rds, priceLabel, "priceRsdAboveStop = " + str.tostring(priceRsdAboveStop)) //simple_label(bar_1_half, priceLabel, "priceRsdAbove = " + str.tostring(priceRsdAbove)) for iRSD = priceRsdAboveStopIdx to priceRsdAboveIdx widthr := widthr + 1 priceRsdNow := 0.0 priceRsdStep := array.get(rsdPuetzUWS, iRSD) while (priceRsdNow <= priceRsdMax) and (iStop < 300) if priceRsdMin <= priceRsdNow line.new(last_bar_index - n_bars, priceRsdNow, last_bar_index, priceRsdNow, color=color.black, width=widthr) //barFirst_label(0.70, priceRsdNow, y_offset, str.tostring(priceRsd_to_priceNormal(priceRsdNow), '#')) //barFirst_label(0.50, priceRsdNow, y_offset, str.tostring(priceRsd_to_priceNormal(priceRsdNow), '#')) barLast_label(priceRsdNow, " " + str.tostring(priceRsd_to_priceNormal(priceRsdNow), '#')) priceRsdNow := priceRsdNow + priceRsdStep iStop := iStop + 1 if barstate.islast drawPriceFrac() // line.new(last_bar_index - n_bars, priceRsdNow, last_bar_index, priceRsdNow, color=color.black, width=iRSD + 1) // barFirst_label(0.70, priceRsdNow, y_offset, str.tostring(priceRsd_to_priceNormal(bar_9_10th, priceRsdNow), '#')) // barFirst_label(0.50, priceRsdNow, y_offset, str.tostring(priceRsd_to_priceNormal(bar_1_half, priceRsdNow), '#')) // 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 // 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) // 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 // 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). // [lambdaPuetzUWS, rsdPuetzUWS] defined in setup section above // find the lambdaPuetzUWS index of the largest ary_t_length fits into the chart timescale t_lengthMaxFitIdx() => max = 0 for j = 0 to 14 if array.get(lambdaPuetzUWS, j) < t_lengthYear max := j max // timeLambdaYearL - active lambdaPuetzUWS for the current timescale [D, 5D, W, M, ...] timeLambdaYearL = array.new_float(5, 0.0) timeLambdaUnixL = array.new_int(5, 0) int timeLamdaMaxIdx = 0 init_timeLambdaL() => lambdaYear = 0.0 for j = 0 to 4 lambdaYear := array.get(lambdaPuetzUWS, timeLamdaMaxIdx - 2 + j) array.set(timeLambdaYearL, j, lambdaYear) array.set(timeLambdaUnixL, j, math.round(lambdaYear * t_year_to_millisecs)) // Jun2022 timePhi - not used yet.I am actually reluctant to going astray with optimization, // when I don't understand the results, and I'm fighting to better understand Pine Script. // phi = time [lag, phase angle], not currently implemented // these are simply fit to each of 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) //timePhi = array.new_float(5, 0.0) //init_timePhi() => , , , , // for j = 0 to 4 // array.set(timePhi, j, array.get(UWS_phi, timeLamdaMaxIdx - 2)) // 14Jun2022 if statement didn't work //if barstate.isfirst // timeLamdaMaxIdx := t_lengthMaxFitIdx() // init_timeLambdaL() // //init_timePhi() timeLamdaMaxIdx := t_lengthMaxFitIdx() init_timeLambdaL() //init_timePhi() // write debug information to chart : //debugTimeFrac() => // priceLabel := priceRsdMax - 3*txtLineHeight // simple_label(bar_2_3rds, priceLabel, "timeIdx = " + str.tostring(timeIdx)) // simple_label(bar_1_half, priceLabel, "timeLamdaMaxIdx = " + str.tostring(timeLamdaMaxIdx)) // priceLabel := priceRsdMax - 4*txtLineHeight // simple_label(bar_2_3rds, priceLabel, "t_lengthYear = " + str.tostring(t_lengthYear)) // simple_label(bar_1_half, priceLabel, "t_lengthUnix = " + str.tostring(t_lengthUnix)) // priceLabel := priceRsdMax - 5*txtLineHeight // simple_label(bar_2_3rds, priceLabel, "t_cycle = " + str.tostring(t_cycle)) // simple_label(bar_1_half, priceLabel, "t_mod = " + str.tostring(t_mod)) // find last, closest] spike in t_lengthUnix //+--+ // drawTimeFrac [spikes, label]s (spikes = verticalLines) // 12May2022 initial, 19May2022 generalized for [Fibonacci, Liebnitz, Puetz] // 19May2022 Half-UWS spike is NOT provided yet // inputs tab - cannot find anywhere for : // fracTyp = input.string(defval="Fibonacci", title="fracTyp", options= ["Fibonacci", "Liebnitz", "Puetz"]) // skip daily chart, as SP500 [t_lengthUnix, n_bars] seem messed up // (maybe not available by minute or whatever) // plot the UWS cycle times (not yet the HUWS) // from Setup (reminder) : // float t_year_to_millisecs = 1000*60*60*24*365.25 float t_shiftYears = 0.05 drawTimeFrac() => bool flagSpike = true int t_cycle = 0 int time_now = 0 int t_mod = 0 int t_spike = 0 int n_spikes = 0 float y_offBase = 0.0 float y_offset = 0.0 float priceLabel = 0.0 for iUWS = 0 to 4 flagSpike := true t_cycle := array.get(timeLambdaUnixL, iUWS) if flag_1871 time_now := t_unix01Jan1970_to_unix01Jul1929(timenow) else time_now := timenow t_mod := math.floor(((time_now / t_cycle) % 1) * t_cycle) //if iUWS == 2 // debugTimeFrac() 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, priceRsdMin, t_spike, priceRsdMax, xloc = xloc.bar_time, color=color.black, width=iUWS + 1) y_offset := (y_offBase - 1 - iUWS)*txtLineHeight/2 time_label(t_spike, priceRsdMax, y_offset, " " + str.tostring(iUWS)) t_spike := t_spike - t_cycle if barstate.islast drawTimeFrac() // reminder - defined earlier //bar_2_3rds = last_bar_index - math.round(n_bars*2/3) //bar_1_half = last_bar_index - math.round(n_bars /2) //bar_3_8ths = last_bar_index - math.round(n_bars*3/8) //bar_1_qrtr = last_bar_index - math.round(n_bars /4) //bar_1_8ths = last_bar_index - math.round(n_bars /8) // simple_label(bar_2_3rds, priceLabel, "timeframe.period = " + timeframe.period) // y_offset := (y_offBase - 1 - i_spike)*txtLineHeight // Create a legend showing periods for fractal depths if barstate.islast periodLabel = "error" period = 0.0 y_offBase = -3.0 y_offset = 0.0 // y_offset := y_offBase*txtLineHeight // barFirst_label(float barFractionFrmRight, float serPrice, float priceOffset, string txt) => barFirst_label(0.85, priceRsdMax, y_offset, "Puetz timeFractal [depth, period]s") for iUWS = 0 to 4 period := array.get(timeLambdaYearL, 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 " // timeBarOffsets are backwards from a specified bar_index // priceOffsets are : + = upward; - = downward y_offset := (y_offBase - 1 - iUWS)*txtLineHeight // 27May2022 cannot use parenthesis in labels? barFirst_label(0.85, priceRsdMax, y_offset, str.tostring(iUWS) + ". " + str.tostring(period, '#.000') + " " + periodLabel) // endcode