Stocks High Low Close Open Trace

Tracking the daily price of stocks uses a "High/Low/Close/Open" graph, which shows all 4 daily prices on one day. See the attached image for an example graph.

This code snippet adds an "Append High Low close Open Trace" item to Igor's Graph menu, and also two submenus for controlling trace thickness and color. The submenus are warranted because the trace's color and thickness are controlled by multiple trace settings, and it makes it easier to ensure they're all set to the same values.

Igor 6.2's custom markers feature makes this trace possible: it draws the open and close markers as, essentially, half-markers, pointing to the left (for the opening price) or the right (for the closing price).

The snippet is not very sophisticated: it creates a wave in the current data folder that combines the high and low price waves into one trace.

Input data is a set of 5 equal length waves: {high price, low price, close price, open price} vs date

The output adds a 6th high/low wave graphed instead of the individual high price and low price wave.

#pragma rtGlobals=2     // Use modern global access method.
#pragma IgorVersion=6.2 // for markerHook

Menu "Graph", dynamic
    Submenu "High Low Close Open Trace"
        "Append High Low Close Open Trace", mAppendHighLowCloseOpen()
        Submenu "Line Sizes"
            HighLowCloseOpenLineSizesMenu(), /Q, DoHighLowCloseOpenLineSize()
        End
        Submenu "Color"
            HighLowCloseOpenColorMenu(),/Q, DoHighLowCloseOpenColor()
        End
    End
End

Function OpenCloseMarkerProc(s)
    STRUCT WMMarkerHookStruct &s
   
    if( s.marker > 3 )
        return 0
    endif

    Variable overhang= s.penThick/2
    Variable size= s.size - overhang
    if( s.marker == 0 )         // open
        DrawLine s.x-size, s.y, s.x+overhang , s.y
    elseif( s.marker == 1 )     // close
        DrawLine s.x-overhang, s.y, s.x+size, s.y
    endif
    return 1
End

Constant kOpenMarker =100
Constant kCloseMarker =101
StrConstant ksHighLowCloseOpenUserDataName="WMHighLowCloseOpenData"

static Function HaveHighLowCloseOpen(graphName)
    String graphName
   
    if( strlen(graphName) == 0 )
        return 0
    endif
    DoWindow $graphName
    if( V_Flag == 0 )
        return 0
    endif
    String traces= TraceNameList(graphName, ";", 1)
    Variable i, n= ItemsInList(traces)
    for(i=0; i<n; i+=1 )
        String traceName= StringFromList(i,traces)
        String userData= GetUserData(graphName, traceName, ksHighLowCloseOpenUserDataName)
        strswitch(userData)
            case "open":
            case "close":
            case "high/low":
                return 1    // have at least one open/close/high/low trace
                break
        endswitch
    endfor
    return 0
End

Function/S HighLowCloseOpenColorMenu()
    String colorMenu= "*COLORPOP*"
    if( !HaveHighLowCloseOpen(WinName(0,1)) )
        colorMenu=  "\M1:(:"+colorMenu
    endif
    return colorMenu
End

Function/S HighLowCloseOpenLineSizesMenu()

    String sizes="0.5;1;2;3;4;5;6;7;8;9;"
    if( !HaveHighLowCloseOpen(WinName(0,1)) )
        Variable i, n= ItemsInList(sizes)
        String disabledSizes=""
        for(i=0; i<n; i+=1 )
            String size= StringFromList(i,sizes)
            disabledSizes +=  "\M1:(:"+size+";"
        endfor
        sizes= disabledSizes
    endif
    return sizes
End

Function DoHighLowCloseOpenLineSize()
    GetLastUserMenuInfo
    Variable lineSize= str2num(S_Value)
    SetHighLowCloseOpenLineSize(lineSize)
End

Function DoHighLowCloseOpenColor()
    GetLastUserMenuInfo
    SetHighLowCloseOpenColor(V_Red, V_Green, V_Blue)
End

Function SetHighLowCloseOpenColor(red, green, blue)
    Variable red, green, blue
   
    // find all the traces related to high-low-open-close and change the line size or marker stroke size.
    String graphName= WinName(0,1)
    if( strlen(graphName) == 0 )
        Beep
        return 0
    endif
    String traces= TraceNameList(graphName, ";", 1)
    Variable i, n= ItemsInList(traces)
    for(i=0; i<n; i+=1 )
        String traceName= StringFromList(i,traces)
        String userData= GetUserData(graphName, traceName, ksHighLowCloseOpenUserDataName)
        strswitch(userData)
            case "open":
            case "close":
            case "high/low":
                ModifyGraph/W=$graphName rgb($traceName)=(red, green, blue)
                break
        endswitch
    endfor
End


Function SetHighLowCloseOpenLineSize(lineSize)
    Variable lineSize
   
    // find all the traces related to high-low-open-close and change the line size or marker stroke size.
    String graphName= WinName(0,1)
    if( strlen(graphName) == 0 )
        Beep
        return 0
    endif
    String traces= TraceNameList(graphName, ";", 1)
    Variable i, n= ItemsInList(traces)
    for(i=0; i<n; i+=1 )
        String traceName= StringFromList(i,traces)
        String userData= GetUserData(graphName, traceName, ksHighLowCloseOpenUserDataName)
        strswitch(userData)
            case "open":
            case "close":
                ModifyGraph/W=$graphName mrkThick($traceName)=lineSize, msize($traceName)=lineSize*3
                break
            case "high/low":
                ModifyGraph/W=$graphName lsize($traceName)=lineSize
                break
        endswitch
    endfor
End

Proc mAppendHighLowCloseOpen(wHigh, wLow, wClose, wOpen, wDays)
    String wHigh, wLow, wClose, wOpen, wDays
    Prompt wHigh, "High Prices", popup, WaveList("*",";","DIMS:1") 
    Prompt wLow, "Low Prices", popup, WaveList("*",";","DIMS:1")
    Prompt wClose, "Close Prices", popup, WaveList("*",";","DIMS:1")
    Prompt wOpen, "Open Prices", popup, WaveList("*",";","DIMS:1") 
    Prompt wDays, "Days", popup, WaveList("*",";","DIMS:1")+";_none_;"  // can be string or numeric wave or _none_

    AppendHighLowCloseOpen($wHigh, $wLow, $wClose, $wOpen, $wDays)
End

Function AppendHighLowCloseOpen(wHigh, wLow, wClose,  wOpen,wDays)
    Wave wHigh, wLow, wOpen, wClose
    Wave/Z wDays

    String graphName= WinName(0,1)
    if( strlen(graphName) == 0 )
        DoAlert 0, "Make a graph, first!"
        return 0
    endif
   
    String outName= CleanupName(NameOfWave(wHigh)[0,14]+"_"+NameOfWave(wLow)[0,14],1)

    if( !WaveExists(wDays) )
        Variable n= numpnts(wOpen)
        String daysName= CleanupName(outName[0,25]+"_days",1)
        Make/O/N=(n) $daysName= p+1 // 1-n
        WAVE wDays= $daysName
    endif

    SetWindow $graphName markerHook={OpenCloseMarkerProc,kOpenMarker,kCloseMarker}
    AppendToGraph/W=$graphName wOpen,wClose vs wDays
    String openTraceName= NameOfWave(wOpen)
    String closeTraceName= NameOfWave(wClose)
    ModifyGraph/W=$graphName mode($openTraceName)=3, mode($closeTraceName)=3
    ModifyGraph/W=$graphName marker($openTraceName)=kOpenMarker,marker($closeTraceName)=kCloseMarker
    ModifyGraph/W=$graphName mrkThick($openTraceName)=1,mrkThick($closeTraceName)=1

    //  Make this work: String userData= GetUserData(graphName, $openTraceName, ksHighLowCloseOpenUserDataName)
    ModifyGraph/W=$graphName userData($openTraceName)={$ksHighLowCloseOpenUserDataName, 0, "open"}
    ModifyGraph/W=$graphName userData($closeTraceName)={$ksHighLowCloseOpenUserDataName, 0, "close"}

    WAVE  wHighLow= fMakeHighLowWave(wHigh, wLow, outName)
    String dayOutName= CleanupName(NameOfWave(wDays)[0,14]+"_4HiLo",1)
    WAVE wHiLoDays= fMakeHighLowDays(wDays, dayOutName)
   
    AppendToGraph/W=$graphName wHighLow vs wHiLoDays
    ModifyGraph/W=$graphName mode($outName)=0
    ModifyGraph/W=$graphName userData($outName)={$ksHighLowCloseOpenUserDataName, 0, "high/low"}
End

Function/WAVE fMakeHighLowWave(wHigh, wLow, outName)
    Wave wHigh, wLow
    String outName
   
    Duplicate/O wHigh, $outName/WAVE=wout
    Variable n=numpnts(wHigh)
    Redimension/N=(3*numpnts(wHigh)) wout
    wout[0;3] = wHigh[p/3]      // interleave high first
    wout[1;3] = wLow[(p-1)/3]   // then low
    wout[2;3] = NaN             // then gap

    return wout
End

Function/WAVE fMakeHighLowDays(wDay, dayOutName)
    Wave wDay   // can be text or numeric wave
    String dayOutName

    Duplicate/O wDay, $dayOutName/WAVE=wout
    Variable n=numpnts(wDay)
    Redimension/N=(3*n) wout
    wout= wDay[trunc(p/3)]
   
    return wout
End

Window OpenCloseHighLowStyle() : GraphStyle
    PauseUpdate; Silent 1       // modifying window...
    ModifyGraph/Z mode[0]=3,mode[1]=3
    ModifyGraph/Z marker[0]=100,marker[1]=101
    ModifyGraph/Z lSize[2]=3
    ModifyGraph/Z rgb[0]=(1,16019,65535),rgb[1]=(1,16019,65535),rgb[2]=(1,16019,65535)
    ModifyGraph/Z msize[0]=9,msize[1]=9
    ModifyGraph/Z mrkThick[0]=3,mrkThick[1]=3
    ModifyGraph/Z grid(bottom)=1
    ModifyGraph/Z nticks(bottom)=10
    ModifyGraph/Z axOffset(bottom)=-1.66667
    ModifyGraph/Z tkLblRot(bottom)=90
    ModifyGraph/Z manTick(bottom)={3450384000,1,0,0,day},manMinor(bottom)={0,50}
    ModifyGraph/Z dateInfo(bottom)={0,0,0}
    Label/Z bottom " "
    SetWindow kwTopWin,markerHook={OpenCloseMarkerProc,100,101}
EndMacro
   
Macro MakeHighLowCloseOpenDemoData()

    Variable n=20
    Make/O/D/N=(n) day
    // start at midnight+1 second
    String todaysDate= Secs2Date(datetime, -2, ";")
    Variable year= str2num(StringFromList(0,todaysDate))
    Variable month= str2num(StringFromList(1,todaysDate))
    Variable today= str2num(StringFromList(2,todaysDate))
    today= date2secs(year, month, today)
   
    day= today+p*60*60*24  
    SetScale d, 0,0,"dat", day
    Make/O/N=(n) openPrice, highPrice, lowPrice, closePrice
    closePrice = 100+gnoise(4)
    openPrice[1,]= closePrice[p-1]
    openPrice[0] = closePrice[0]-gnoise(2)
    lowprice= (openPrice+closePrice)/2 + gnoise(max(1,abs(openPrice-closePrice)))
    lowPrice= min(lowPrice, min(openPrice,closePrice))
    highprice= (openPrice+closePrice)/2 + gnoise(max(1,abs(openPrice-closePrice)))
    highPrice= max(highPrice, max(openPrice,closePrice))
    Edit day, openPrice, lowPrice, highPrice, closePrice
    ModifyTable format(day)=6
    Display
    DoAlert 0, "Choose \"Append High Low Close Open Trace\" from the Graph's \"High Low Close Open Trace\" menu."
End
HighLowCloseOpen.ipf (8.02 KB)

Forum

Support

Gallery

Igor Pro 9

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More