Pyrapoint is a trading methodology developed by Don Hall and it is based on many of the theories set forth by WD Gann. Mr. Hall has published a book which outlines his methodology in detail and he also organizes seminars at various times during the year. The book is called "Pyrapoint" and can be purchased through the TradersWorld web site. This PyraTool script is a template that can be used in conjunction with Mr. Hall's Pyrapoint methodology. Based upon an anchor point that you select, it will draw the price/time columns overlaid on your chart. Please note that this is still a work-in-progress and I will be posting updates along the way as I figure out how to implement some of the items on my to-do list. The biggest issue with the current version is that the 'time' calculation (e.g., the # of bars until the next vertical time line) is not correct once you go past 180-degrees in either direction. For intraday usage this will rarely, if ever, be an issue because it is unlikely that the anchor point is going to be 180-degrees away from current price action. However, on daily charts it will be an issue and you need to keep it in mind. ===================================================================== Various parameters can be adjusted via the eSignal Edit Studies option: frAnchorBar: The offset of the actual bar from which the PyraTool study should be started. This is the offset from the first bar of the trading day. So, if a swing-high occurs on the 4th bar of the current trading day and you want to start your study from this bar, you would enter the value of 3 into the Edit Studies dialog (the first bar of the day is 0, second is 1, etc.). You can also offset backwards to a bar from the previous trading day by making this a negative value. (Note: see the frUseButtons option below for a faster alternative to changing the anchor point). frDegrees: The degree setting that you wish to use for the calculations. Valid values are 2, 5, 11, 22, 45, 90, 180 and 360. Note that the 2, 5, 11 and 22 values are converted by the script to be 2.8125, 5.625, 11.25 and 22.50 respectively. frPrice: The point on the anchor bar (e.g., the high or the low) that you wish to place the anchor. Value values are 0 (for low) and 1 (for high). frUseButtons: This option will allow you to display buttons on the chart so that you can quickly change settings as well as to reposition the anchor point. frShowLegend: Display the configuration legend at bottom-right of chart. Default value is 1 (display legend). Set to 0 to disable display of legend. Button Descriptions: (-) Click on this button and the button bar will be collapsed. (+) to restore. deg-- Decrease the degree setting (down to 2.8125) deg++ Increase the degree setting (up to 360) Low Set the anchor point at the Low price of current bar. High Set the anchor point at the High price of current bar. > Shift anchor right 1 bar. < Shift anchor left 1 bar. >> Shift anchor right to next pivot point << Shift anchor left to previous pivot point Note: When you use the last two options (e.g., shift to next/prior pivot point), the High or Low setting will be set automatically depending upon whether it is a pivot-high or a pivot-low. If you come across any fixes or have any ideas on how to spruce it up, I would appreciate it if you would let me know (c.kryza@gte.net). Dislaimer: For educational purposes only! Obviously, no guarantees whatsoever and use at your own risk. **********************************************************************/ //Global Variables var PPVersion ="Version 1.8.0, PyraTool"; var PPStartBar =-999; //This is distance from first bar of day var PPDegrees = 45; //Degrees we are currently plotting var PPPrice = 1; //Use High price for calcs (0=low) var PPLevels = 8; //Default # of levels to draw in each column var PPUseButtons = 1; //Use config buttons var PPShowLegend = 1; //Display the config legend var PPTopLevel = -1 //highest level currently recording var PPTimeOffset = 0; //append as we build each new grid var PPCurLoLevel = -99999; //lowest price level displayed in current column var PPCurHiLevel = 99999; //highest price level displayed in current column var nLvlBuffer = 2; //used to padd additional levels in the current column var nCurWidth = 0; //current 'time' value (in bars) var nCurBorder = 0; var nCurPPStart; var aPLevelsPlus = new Array(); //array to hold positive price levels (above 0-degrees) var aTLevelsPlus = new Array(); //array to hold positive timeframes (above 0-degrees) var aPLevelsMinu = new Array(); //array to hold negative price levels (below 0-degrees) var aTLevelsMinu = new Array(); //array to hold negative timeframes (below 0-degrees) var aLabels = new Array("", "<>", "<", ">", "High", "Low", "deg++", "deg--", "(-)"); var bButtonPressed = false; //was a button just pressed? var bFirstDisplay = true; //True on script load var bIsDirty = true; //used to maintain variables between button presses var bCollapsed = false; //is the button-bar collapsed? var grID; var MaxDegrees = 22.5; //Adjust this up or down. Will force the number of levels displayed. //Valid values for MaxDegrees are 11.25, 22.5, 45.0, 90.0 and 180.0; //Color Settings (adjust as you see fit) var UpDiagColor = Color.green; //diagonal color var DnDiagColor = Color.red; //diagonal color var BoxColor = Color.lightgrey; //box color var PriceColor = Color.blue; //price display color var Thickness = 1; //box bar thickness //State Maint variables var oSettings = new Array(); var sUnique = "ppp"; //unique prefix to identify this script //== PreMain function required by eSignal to set things up function preMain() { setPriceStudy(true); setStudyTitle("PyraTool"); setCursorLabelName("Pyra"); setShowCursorLabel(false); setComputeOnClose(); bIsDirty = true; grID = 0; } //main processing function function main(frAnchorBar, frDegrees, frPrice, frUseButtons, frShowLegend) { var x,y,z,xx; var nHiLite; var nFont; var dtTime; var dtToday; var nFlags; var Hrs, Min; var Yr, Yr1; var Mo, Mo1; var Da, Da1; var nLookBack; var nIndex; var aLows, aHighs; var aCloses, aOpens; var nHHigh, nLLow; var nPrice; var nCurAnchor = 0.0; var nCounter; var nCurX; var nFirstBar; var dtTimeTarg; var thisHash; if (getBarState() == BARSTATE_ALLBARS) { return null; } //wait until bars are drawn... if (( getCurrentBarIndex() < -1 ) && bButtonPressed == false ) { return; } //if settings changed, update our state information if (bIsDirty==true) { thisHash = doHash( main ); if ((isSameSymbol("ppp")==true) && (thisHash != getGlobalValue( sUnique+"Hash" ))) { setSettings( frAnchorBar, frDegrees, frPrice, frUseButtons, frShowLegend ); } } //get the state information, if it doesn't match our current params setGlobalValue( sUnique+"Hash", doHash( main ) ); x = getSettings( oSettings, 5 ); if (x>0) { for (y=0; y<5; y++) { if (y==0) frAnchorBar = oSettings[y]; if (y==1) frDegrees = oSettings[y]; if (y==2) frPrice = oSettings[y]; if (y==3) frUseButtons = oSettings[y]; if (y==4) frShowLegend = oSettings[y]; } } setGlobalValue( sUnique+"LastSymb", getSymbol()+getInterval() ); bButtonPressed = false; //Reset program options if criteria passed directly to main function if (bIsDirty==true) { bIsDirty=false; if (frAnchorBar != null) { if (isNaN(frAnchorBar)) { displayError("Error: AnchorBar must be number."); return; } PPStartBar = frAnchorBar; } if (frDegrees != null) { if ((frDegrees != 2) && (frDegrees != 5) && (frDegrees != 11) && (frDegrees != 22) && (frDegrees != 45) && (frDegrees != 90) && (frDegrees != 180) && (frDegrees != 360)) { displayError(" Error: Invalid Degrees selection! (2, 5, 11, 22, 45, 90, 180 or 360) "); return; } PPDegrees = frDegrees; } if (frPrice != null) { if ((frPrice !=0) && (frPrice != 1)) { displayError("Error: Invalid Price selection! (0 or 1 only)"); return; } PPPrice = frPrice; } if (frUseButtons != null) { if ((frUseButtons !=0) && (frUseButtons != 1)) { displayError("Error: Invalid Buttons selection! (0 or 1 only)"); return; } PPUseButtons = frUseButtons; } if (frShowLegend != null) { if ((frShowLegend !=0) && (frShowLegend != 1)) { displayError("Error: Invalid ShowLegend selection! (0 or 1 only)"); return; } PPShowLegend = frShowLegend; } } //convert rounded Degrees to the correct value if (PPDegrees == 22) PPDegrees = 22.50; if (PPDegrees == 11) PPDegrees = 11.25; if (PPDegrees == 5) PPDegrees = 5.625; if (PPDegrees == 2) PPDegrees = 2.8125; //generate error if Tick data is loaded //(As of Build 544, the 'drawLine' series of functions do not work correctly //when tick data is loaded.) if (isRawTick()==true) { displayError("Sorry. Tick data is not supported at this time."); return; } //get datestamp of last bar on record dtTime = getValue("Time"); Yr1 = dtTime.getFullYear(); Mo1 = dtTime.getMonth(); Da1 = dtTime.getDate(); nFirstBar = ( getFirstBarIndexOfDay(dtTime) ); //if PPStartBar at default value, set it to current bar -1 if ( PPStartBar == -999 ) { PPStartBar = Math.abs( nFirstBar ) - 1; } //check to make sure a valid price offset was passed. //if not using buttons, display an error and get out //if using buttons, simply change offset to most recent bar if ( PPStartBar > Math.abs( nFirstBar ) ) { if (PPUseButtons==0) { displayError("Error: Invalid bar offset selected (frPrice)."); return; } PPStartBar = Math.abs( nFirstBar ); } //Our initial Lookback will be back to the bar //that is our anchor point (PPAnchor). nCurPPStart = Math.abs( nFirstBar + PPStartBar ); nLookBack = nCurPPStart; nLookBack = (nLookBack<100) ? 100 : nLookBack+1; //debugPrint("PPStart: "+PPStartBar+"\n"); //debugPrint("nCurPPStart: "+nCurPPStart+"\n"); //debugPrint("NumBars: "+getNumBars()+"\n"); //debugPrint("nLookBack: "+nLookBack+"\n"); //Our offset is zero nIndex = 0; grID = 0; PPTimeOffset = 0; nCurWidth = 0; PPTopLevel = -1; nLvlBuffer = 2; PPLevels = 8; //Our anchor will be based on either the high or the low //of a specific bar. Load all of the bars back to our //anchor bar. aHighs = getValueAbsolute("High", nIndex, -nLookBack); aLows = getValueAbsolute("Low", nIndex, -nLookBack); if( aHighs==null ) { displayError( "Error retrieving data."); return; } nHHigh = -999999.0; nLLow = 999999.0; //get highest-high and lowest-low x=0; while(xnHHigh) nHHigh = aHighs[x]; if (aLows[x]= 0) { nPrice = (PPPrice==1) ? aHighs[x] : aLows[x]; dtTimeTarg = getTimeFromPrice( nPrice ); if (nCounter >= dtTimeTarg) { nCurX = x; PPCurHiLevel = -99999.0; PPCurLoLevel = 99999.0; DrawPyraColumn(nCurX, nCurAnchor, nPrice, PPDegrees, PPLevels, 0, aHighs[x], aLows[x]); nCounter = 0; } nCounter++; //if price breaches a grid boundary, redraw and expand the grid if ( (aLows[x] <= PPCurLoLevel) || (aHighs[x] >= PPCurHiLevel) ) { PPLevels++; PPCurHiLevel = -99999.0; PPCurLoLevel = 99999.0; DrawPyraColumn(nCurX, nCurAnchor, nPrice, PPDegrees, PPLevels, 1, aHighs[x], aLows[x]); } x--; } //display our buttons if button feature is turned on if (PPUseButtons == 1) { x=1; z=20; //collapse our buttons and just display the 'restore' button. if (bCollapsed==true) { drawTextAbsolute(1, 20, " (+) " + "@URL=EFS:setRestore", Color.red, Color.grey, Text.BUTTON | Text.RELATIVETOLEFT | Text.RELATIVETOBOTTOM, "Courier New", 11, gID()); } //otherwise, display all of our buttons else { while(x<10) { nTmp = " "+aLabels[x]+" "; z = z+20; y = 6 - nTmp.length; xx=1; while(xx1000) { while(1==1) { nA = nA/10; Norm*=10; if (nA<1000) break; } } else if (nA<100) { while(1==1) { nA = nA*10; Norm/=10; if (nA>=100) break; } } //Hold this thought for second loop hA = nA; xx = 0; //plot upper levels of column (i.e., above 0 degrees) x=0; while(x=(nLL-nDiff)) || (TotDegrees<=MaxDegrees)) { PPCurLoLevel = B; if (PPCurHiLevel==-99999.0) PPCurHiLevel=A; DrawBox(nOffset, A,B,C,D,xx,xx-nDegrees,rnd(A,2),rnd(B,2),null); } } else if (x==(nLevels-1)) { if ((B>=(nLL-nDiff)) || (TotDegrees<=MaxDegrees)) { PPCurLoLevel = B; if (bRedraw==1) { nTmp = PPTimeOffset; } else { nTmp = C+PPTimeOffset; } DrawBox(nOffset, A,B,C,D,null,xx-nDegrees,null,rnd(B,2),nTmp); } aPLevelsMinu[x+1] = rnd(B,2); aTLevelsMinu[x+1] = C; } else { if ((B>=(nLL-nDiff)) || (TotDegrees<=MaxDegrees)) { PPCurLoLevel = B; DrawBox(nOffset, A,B,C,D,null,xx-nDegrees,null,rnd(B,2),null); } } nA = nB; xx-=nDegrees; x++; } //Set our TopLevel PPTopLevel = nLevels; if (bRedraw != 1) PPTimeOffset += C; return; } //== getTimeFromPrice() retrieves the current time offset (in bars) //== for the price that is passed to the function. function getTimeFromPrice( nPrice ) { var x; //walk down upper levels x=PPTopLevel; while(x>=0) { if (nPrice >= aPLevelsPlus[x]) { return( aTLevelsPlus[x] ); } if (nPrice <= aPLevelsMinu[x]) { return( aTLevelsMinu[x] ); } x--; } return; } //== getPrice - return text representation of anchor price type function getPrice( iVal ) { if (iVal==0) return( "Low" ); return( "High" ); } //== Determines if a button was pressed function getButtonPressed(nButtonPressed) { if(nButtonPressed == BUTTON_LEFT) { bIsDirty=true; return(1); } else { return(0); } } //== findPivot will scan backwards or forwards to //== find the prev/next swing high or swing low in the data series function findPivot( nCurOffset, nDirection ) { var x,y; var nLvls; var nPivot; var nvH,nvL; var nLB; var nPad; //define size of a pivot (x-bars on either side lower or higher) nPivot = 4; //scan backwards for pivots if ( nDirection == -1 ) { nLB = 100; nPad = nCurOffset-(nPivot-1)>=0 ? (nPivot-1) : 0; nCurOffset = nCurOffset - nPad; nvH = getValueAbsolute("High", -nCurOffset, -(nLB)); nvL = getValueAbsolute("Low", -nCurOffset, -(nLB)); if( nvH==null ) { return(-1); } x=0; while(xnPivot+1) { nLvls = 0; for(y=0; ynvL[x-nPivot]) nLvls++; if (nvL[x-(y+(nPivot+1))]>=nvL[x-nPivot]) nLvls++; } if (nLvls>((nPivot*2)-1)) { PPPrice = 0; return( (x-nPivot)-nPad ); } nLvls = 0; for(y=0; y((nPivot*2)-1)) { PPPrice = 1; return( (x-nPivot)-nPad ); } } x++; } } //scan forward for pivots if ( nDirection == 1 ) { nLB = nCurOffset + (nPivot-1); nvH = getValueAbsolute("High", 0, -(nLB)); nvL = getValueAbsolute("Low", 0, -(nLB)); if( nvH==null ) { return(-1); } x=nLB; while(x>=0) { if ((x-nPivot+1)>(nPivot+1)) { nLvls = 0; for(y=0; ynvL[x-nPivot]) nLvls++; if (nvL[x-(y+(nPivot+1))]>=nvL[x-nPivot]) nLvls++; } if (nLvls>((nPivot*2)-1)) { PPPrice = 0; return( (nLB-(nPivot-1)) - (x-nPivot) ); } nLvls = 0; for(y=0; y((nPivot*2)-1)) { PPPrice = 1; return( (nLB-(nPivot-1)) - (x-nPivot) ); } } x--; } } return (-1); } //== event handler for left-mouse double-click function onLButtonDblClk( barIndex, yValue) { var nTmp; var nHigh; var nLow; //get the high/low of bar user clicked on nHigh = high(barIndex); nLow = low(barIndex); //disregard double-clicks if they are more that 0.5% away from price action if ( yValue > nHigh*1.005 || yValue < nLow*0.995 ) return; //get index to first bar of day nTmp = ( getFirstBarIndexOfDay(getValue("rawtime")) ); //set the anchor to either high or low of bar, depending upon which is closer //to the exact point where user clicked PPPrice = ( Math.abs( yValue-nHigh ) < Math.abs( yValue-nLow ) ) ? 1 : 0 ; PPStartBar = barIndex - nTmp; bButtonPressed = true; main(PPStartBar, null, PPPrice, null); return; } //== event handler - shift left to the next hi/lo pivot function set1( nButtonPressed ) { var ret; if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; ret = findPivot( nCurPPStart, -1 ); PPStartBar = (ret<0) ? PPStartBar-10 : PPStartBar-ret; main(PPStartBar, null, PPPrice, null, null); } return; } //== event handler - shift right to the next hi/lo pivot function set2( nButtonPressed ) { var ret; if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; ret = findPivot( nCurPPStart, 1 ); PPStartBar = (ret<0) ? PPStartBar+10 : PPStartBar+ret; main(PPStartBar, null, PPPrice, null, null); } return; } //== event handler - shift left 1 bar function set3( nButtonPressed ) { if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; PPStartBar-=1; main(PPStartBar, null, PPPrice, null, null); } return; } //== event handler - shift right 1 bar function set4( nButtonPressed ) { if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; PPStartBar+=1; main(PPStartBar, null, PPPrice, null, null); } return; } //== event handler - use High price for calcs function set5( nButtonPressed ) { if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; PPPrice = 1; main(PPStartBar, null, PPPrice, null, null); } return; } //== event handler - use Low price for calcs function set6( nButtonPressed ) { if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; PPPrice = 0; main(PPStartBar, null, PPPrice, null, null); } return; } //== event handler - increment degrees function set7( nButtonPressed ) { var val; if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; val = Math.floor(PPDegrees*2); if (val>360) val = 360; main(PPStartBar, val, PPPrice, null, null); } return; } //== event handler - decrement degrees function set8( nButtonPressed ) { var val; if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; val = Math.floor( PPDegrees/2 ); if (val<2) val=2; main(PPStartBar, val, PPPrice, null, null); } return; } //== event handler - collapse the buttons function set9( nButtonPressed ) { if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; bIsDirty = false; bCollapsed=true; main(null, null, null, null, null); } return; } //== event handler - restore the buttons function setRestore( nButtonPressed ) { if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; bIsDirty = false; bCollapsed=false; main(null, null, null, null, null); } return; } User is offlineProfile Card Go to the top of the page +Quote Post V Full Edit V Quick Edit sakimonohito post Nov 21 2004, 08:54 PM Post #4 Member Group: Members Posts: 10 Joined: 21-November 04 Member No.: 1,571 //main processing function function main(frAnchorBar, frDegrees, frPrice, frUseButtons, frShowLegend) { var x,y,z,xx; var nHiLite; var nFont; var dtTime; var dtToday; var nFlags; var Hrs, Min; var Yr, Yr1; var Mo, Mo1; var Da, Da1; var nLookBack; var nIndex; var aLows, aHighs; var aCloses, aOpens; var nHHigh, nLLow; var nPrice; var nCurAnchor = 0.0; var nCounter; var nCurX; var nFirstBar; var dtTimeTarg; var thisHash; if (getBarState() == BARSTATE_ALLBARS) { return null; } //wait until bars are drawn... if (( getCurrentBarIndex() < -1 ) && bButtonPressed == false ) { return; } //if settings changed, update our state information if (bIsDirty==true) { thisHash = doHash( main ); if ((isSameSymbol("ppp")==true) && (thisHash != getGlobalValue( sUnique+"Hash" ))) { setSettings( frAnchorBar, frDegrees, frPrice, frUseButtons, frShowLegend ); } } //get the state information, if it doesn't match our current params setGlobalValue( sUnique+"Hash", doHash( main ) ); x = getSettings( oSettings, 5 ); if (x>0) { for (y=0; y<5; y++) { if (y==0) frAnchorBar = oSettings[y]; if (y==1) frDegrees = oSettings[y]; if (y==2) frPrice = oSettings[y]; if (y==3) frUseButtons = oSettings[y]; if (y==4) frShowLegend = oSettings[y]; } } setGlobalValue( sUnique+"LastSymb", getSymbol()+getInterval() ); bButtonPressed = false; //Reset program options if criteria passed directly to main function if (bIsDirty==true) { bIsDirty=false; if (frAnchorBar != null) { if (isNaN(frAnchorBar)) { displayError("Error: AnchorBar must be number."); return; } PPStartBar = frAnchorBar; } if (frDegrees != null) { if ((frDegrees != 2) && (frDegrees != 5) && (frDegrees != 11) && (frDegrees != 22) && (frDegrees != 45) && (frDegrees != 90) && (frDegrees != 180) && (frDegrees != 360)) { displayError(" Error: Invalid Degrees selection! (2, 5, 11, 22, 45, 90, 180 or 360) "); return; } PPDegrees = frDegrees; } if (frPrice != null) { if ((frPrice !=0) && (frPrice != 1)) { displayError("Error: Invalid Price selection! (0 or 1 only)"); return; } PPPrice = frPrice; } if (frUseButtons != null) { if ((frUseButtons !=0) && (frUseButtons != 1)) { displayError("Error: Invalid Buttons selection! (0 or 1 only)"); return; } PPUseButtons = frUseButtons; } if (frShowLegend != null) { if ((frShowLegend !=0) && (frShowLegend != 1)) { displayError("Error: Invalid ShowLegend selection! (0 or 1 only)"); return; } PPShowLegend = frShowLegend; } } //convert rounded Degrees to the correct value if (PPDegrees == 22) PPDegrees = 22.50; if (PPDegrees == 11) PPDegrees = 11.25; if (PPDegrees == 5) PPDegrees = 5.625; if (PPDegrees == 2) PPDegrees = 2.8125; //generate error if Tick data is loaded //(As of Build 544, the 'drawLine' series of functions do not work correctly //when tick data is loaded.) if (isRawTick()==true) { displayError("Sorry. Tick data is not supported at this time."); return; } //get datestamp of last bar on record dtTime = getValue("Time"); Yr1 = dtTime.getFullYear(); Mo1 = dtTime.getMonth(); Da1 = dtTime.getDate(); nFirstBar = ( getFirstBarIndexOfDay(dtTime) ); //if PPStartBar at default value, set it to current bar -1 if ( PPStartBar == -999 ) { PPStartBar = Math.abs( nFirstBar ) - 1; } //check to make sure a valid price offset was passed. //if not using buttons, display an error and get out //if using buttons, simply change offset to most recent bar if ( PPStartBar > Math.abs( nFirstBar ) ) { if (PPUseButtons==0) { displayError("Error: Invalid bar offset selected (frPrice)."); return; } PPStartBar = Math.abs( nFirstBar ); } //Our initial Lookback will be back to the bar //that is our anchor point (PPAnchor). nCurPPStart = Math.abs( nFirstBar + PPStartBar ); nLookBack = nCurPPStart; nLookBack = (nLookBack<100) ? 100 : nLookBack+1; //debugPrint("PPStart: "+PPStartBar+"\n"); //debugPrint("nCurPPStart: "+nCurPPStart+"\n"); //debugPrint("NumBars: "+getNumBars()+"\n"); //debugPrint("nLookBack: "+nLookBack+"\n"); //Our offset is zero nIndex = 0; grID = 0; PPTimeOffset = 0; nCurWidth = 0; PPTopLevel = -1; nLvlBuffer = 2; PPLevels = 8; //Our anchor will be based on either the high or the low //of a specific bar. Load all of the bars back to our //anchor bar. aHighs = getValueAbsolute("High", nIndex, -nLookBack); aLows = getValueAbsolute("Low", nIndex, -nLookBack); if( aHighs==null ) { displayError( "Error retrieving data."); return; } nHHigh = -999999.0; nLLow = 999999.0; //get highest-high and lowest-low x=0; while(xnHHigh) nHHigh = aHighs[x]; if (aLows[x]= 0) { nPrice = (PPPrice==1) ? aHighs[x] : aLows[x]; dtTimeTarg = getTimeFromPrice( nPrice ); if (nCounter >= dtTimeTarg) { nCurX = x; PPCurHiLevel = -99999.0; PPCurLoLevel = 99999.0; DrawPyraColumn(nCurX, nCurAnchor, nPrice, PPDegrees, PPLevels, 0, aHighs[x], aLows[x]); nCounter = 0; } nCounter++; //if price breaches a grid boundary, redraw and expand the grid if ( (aLows[x] <= PPCurLoLevel) || (aHighs[x] >= PPCurHiLevel) ) { PPLevels++; PPCurHiLevel = -99999.0; PPCurLoLevel = 99999.0; DrawPyraColumn(nCurX, nCurAnchor, nPrice, PPDegrees, PPLevels, 1, aHighs[x], aLows[x]); } x--; } //display our buttons if button feature is turned on if (PPUseButtons == 1) { x=1; z=20; //collapse our buttons and just display the 'restore' button. if (bCollapsed==true) { drawTextAbsolute(1, 20, " (+) " + "@URL=EFS:setRestore", Color.red, Color.grey, Text.BUTTON | Text.RELATIVETOLEFT | Text.RELATIVETOBOTTOM, "Courier New", 11, gID()); } //otherwise, display all of our buttons else { while(x<10) { nTmp = " "+aLabels[x]+" "; z = z+20; y = 6 - nTmp.length; xx=1; while(xx1000) { while(1==1) { nA = nA/10; Norm*=10; if (nA<1000) break; } } else if (nA<100) { while(1==1) { nA = nA*10; Norm/=10; if (nA>=100) break; } } //Hold this thought for second loop hA = nA; xx = 0; //plot upper levels of column (i.e., above 0 degrees) x=0; while(x=(nLL-nDiff)) || (TotDegrees<=MaxDegrees)) { PPCurLoLevel = B; if (PPCurHiLevel==-99999.0) PPCurHiLevel=A; DrawBox(nOffset, A,B,C,D,xx,xx-nDegrees,rnd(A,2),rnd(B,2),null); } } else if (x==(nLevels-1)) { if ((B>=(nLL-nDiff)) || (TotDegrees<=MaxDegrees)) { PPCurLoLevel = B; if (bRedraw==1) { nTmp = PPTimeOffset; } else { nTmp = C+PPTimeOffset; } DrawBox(nOffset, A,B,C,D,null,xx-nDegrees,null,rnd(B,2),nTmp); } aPLevelsMinu[x+1] = rnd(B,2); aTLevelsMinu[x+1] = C; } else { if ((B>=(nLL-nDiff)) || (TotDegrees<=MaxDegrees)) { PPCurLoLevel = B; DrawBox(nOffset, A,B,C,D,null,xx-nDegrees,null,rnd(B,2),null); } } nA = nB; xx-=nDegrees; x++; } //Set our TopLevel PPTopLevel = nLevels; if (bRedraw != 1) PPTimeOffset += C; return; } //== getTimeFromPrice() retrieves the current time offset (in bars) //== for the price that is passed to the function. function getTimeFromPrice( nPrice ) { var x; //walk down upper levels x=PPTopLevel; while(x>=0) { if (nPrice >= aPLevelsPlus[x]) { return( aTLevelsPlus[x] ); } if (nPrice <= aPLevelsMinu[x]) { return( aTLevelsMinu[x] ); } x--; } return; } //== getPrice - return text representation of anchor price type function getPrice( iVal ) { if (iVal==0) return( "Low" ); return( "High" ); } //== Determines if a button was pressed function getButtonPressed(nButtonPressed) { if(nButtonPressed == BUTTON_LEFT) { bIsDirty=true; return(1); } else { return(0); } } //== findPivot will scan backwards or forwards to //== find the prev/next swing high or swing low in the data series function findPivot( nCurOffset, nDirection ) { var x,y; var nLvls; var nPivot; var nvH,nvL; var nLB; var nPad; //define size of a pivot (x-bars on either side lower or higher) nPivot = 4; //scan backwards for pivots if ( nDirection == -1 ) { nLB = 100; nPad = nCurOffset-(nPivot-1)>=0 ? (nPivot-1) : 0; nCurOffset = nCurOffset - nPad; nvH = getValueAbsolute("High", -nCurOffset, -(nLB)); nvL = getValueAbsolute("Low", -nCurOffset, -(nLB)); if( nvH==null ) { return(-1); } x=0; while(xnPivot+1) { nLvls = 0; for(y=0; ynvL[x-nPivot]) nLvls++; if (nvL[x-(y+(nPivot+1))]>=nvL[x-nPivot]) nLvls++; } if (nLvls>((nPivot*2)-1)) { PPPrice = 0; return( (x-nPivot)-nPad ); } nLvls = 0; for(y=0; y((nPivot*2)-1)) { PPPrice = 1; return( (x-nPivot)-nPad ); } } x++; } } //scan forward for pivots if ( nDirection == 1 ) { nLB = nCurOffset + (nPivot-1); nvH = getValueAbsolute("High", 0, -(nLB)); nvL = getValueAbsolute("Low", 0, -(nLB)); if( nvH==null ) { return(-1); } x=nLB; while(x>=0) { if ((x-nPivot+1)>(nPivot+1)) { nLvls = 0; for(y=0; ynvL[x-nPivot]) nLvls++; if (nvL[x-(y+(nPivot+1))]>=nvL[x-nPivot]) nLvls++; } if (nLvls>((nPivot*2)-1)) { PPPrice = 0; return( (nLB-(nPivot-1)) - (x-nPivot) ); } nLvls = 0; for(y=0; y((nPivot*2)-1)) { PPPrice = 1; return( (nLB-(nPivot-1)) - (x-nPivot) ); } } x--; } } return (-1); } //== event handler for left-mouse double-click function onLButtonDblClk( barIndex, yValue) { var nTmp; var nHigh; var nLow; //get the high/low of bar user clicked on nHigh = high(barIndex); nLow = low(barIndex); //disregard double-clicks if they are more that 0.5% away from price action if ( yValue > nHigh*1.005 || yValue < nLow*0.995 ) return; //get index to first bar of day nTmp = ( getFirstBarIndexOfDay(getValue("rawtime")) ); //set the anchor to either high or low of bar, depending upon which is closer //to the exact point where user clicked PPPrice = ( Math.abs( yValue-nHigh ) < Math.abs( yValue-nLow ) ) ? 1 : 0 ; PPStartBar = barIndex - nTmp; bButtonPressed = true; main(PPStartBar, null, PPPrice, null); return; } //== event handler - shift left to the next hi/lo pivot function set1( nButtonPressed ) { var ret; if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; ret = findPivot( nCurPPStart, -1 ); PPStartBar = (ret<0) ? PPStartBar-10 : PPStartBar-ret; main(PPStartBar, null, PPPrice, null, null); } return; } //== event handler - shift right to the next hi/lo pivot function set2( nButtonPressed ) { var ret; if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; ret = findPivot( nCurPPStart, 1 ); PPStartBar = (ret<0) ? PPStartBar+10 : PPStartBar+ret; main(PPStartBar, null, PPPrice, null, null); } return; } //== event handler - shift left 1 bar function set3( nButtonPressed ) { if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; PPStartBar-=1; main(PPStartBar, null, PPPrice, null, null); } return; } //== event handler - shift right 1 bar function set4( nButtonPressed ) { if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; PPStartBar+=1; main(PPStartBar, null, PPPrice, null, null); } return; } //== event handler - use High price for calcs function set5( nButtonPressed ) { if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; PPPrice = 1; main(PPStartBar, null, PPPrice, null, null); } return; } //== event handler - use Low price for calcs function set6( nButtonPressed ) { if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; PPPrice = 0; main(PPStartBar, null, PPPrice, null, null); } return; } //== event handler - increment degrees function set7( nButtonPressed ) { var val; if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; val = Math.floor(PPDegrees*2); if (val>360) val = 360; main(PPStartBar, val, PPPrice, null, null); } return; } //== event handler - decrement degrees function set8( nButtonPressed ) { var val; if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; val = Math.floor( PPDegrees/2 ); if (val<2) val=2; main(PPStartBar, val, PPPrice, null, null); } return; } //== event handler - collapse the buttons function set9( nButtonPressed ) { if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; bIsDirty = false; bCollapsed=true; main(null, null, null, null, null); } return; } //== event handler - restore the buttons function setRestore( nButtonPressed ) { if ( getButtonPressed( nButtonPressed ) == 1 ) { bButtonPressed = true; bIsDirty = false; bCollapsed=false; main(null, null, null, null, null); } return; }