NYCJUG/2009-02-10/pf.ijs

From J Wiki
Jump to: navigation, search

Some code for creating a "point-and-figure" chart from Dow Jones price data for 2007 and 2008.

NB. pf.ijs - standard "Point & Figure" charting algorithm with optional dating added
NB. by Harvey E. Hahn -- 23-25,29-31 Jan; 1,4,6-7 Feb 2009

NB. Initial datatype prefixes used to keep names straight:
NB.    "b" for boxed
NB.    "s" for string (literal)
NB.    "n" for numeric

require 'files'

pfchart=: 3 : 0

NB. constants (should be input by user instead?):
nBox=. 150    NB. size of charting box (related to nMaxRows below))
nRevBoxes=. 3    NB. number of boxes needed for reversal
nMaxColumns=. 125
nMaxRows=. 50    NB. this can affect value of "nBox" if calculated by formula
nShowDate=. 1    NB. flag to display dates or not

NB. initialize variables:
nBoxHigh=. 0
nBoxLow=. 0
nHigh=. 0
nLow=. 0
nClose=. 0
nNewHigh=. 0
nNewLow=. 0
nCurrCol=. 0
nFirst=. 1    NB. flag is turned "off" (false) after first entry
nXCol=. 1
nOCol=. 0
nColType=. nXCol
sLastMonthPlotted=. ''
sLastYearPlotted=. ''
sYr=. ''
sMn=. ''
nMon=. 0
sMonth=. ''
nRowOffset=. 0

if. (1 = nShowDate) do.
 nMaxRows=. nMaxRows + 4  NB. 4 extra rows needed for 4 vertical digits of year
 nRowOffset=. 4
end.

sChart=. (nMaxRows,nMaxColumns) $ ' '    NB. chart array

NB. read in (Yahoo) market data file and cull out date/high/low/close values:
NB. bMktData=. readcsv (jpath '~user\data\DJI-r-pf.csv')
bMktData=. readcsv 'DJI2007-2008.csv'
bDate=.  0 {"1 bMktData   NB. column 0 is date (format: yyyy-mm-dd)
bHigh=.  2 {"1 bMktData   NB. column 2 is high
bLow=.   3 {"1 bMktData   NB. column 3 is low
bClose=. 4 {"1 bMktData   NB. column 4 is close

NB. two ways chart range might be done --
NB.   (1) look for max and min of prices (nBox = (max-min)/boxsize),
NB. or
NB.   (2) take first price and calculate range of 50% higher
NB.       and 50% lower

NB. for testing purposes (DJIA 2007-2008):
nChartLow=. 7000
nChartHigh=. 14500    NB. midpoint = 10750, nBox = 150

for_i. i.((#bMktData)-1) do.

 sYr=. 4 {. > i { bDate
 sMn=. 2 {. 5 }. > i { bDate
 nMon=. ". sMn
 if. (9 < nMon) do.
   sMonth=. (nMon-10) { 'abc'
 else.
   sMonth=. ": 1 } sMn
 end.
 nHigh=. (". > i { bHigh) - nChartLow
 nLow=. (". > i { bLow) - nChartLow
 nClose=. (". > i { bClose) - nChartLow

 if. (nChartHigh < (". > i { bHigh)) +. (nChartLow > (". > i { bLow)) do.
   sChart=. |. sChart
   smoutput 'Data for ',(> i { bDate),' exceeded chart range'
   return.
 end.

 NB. (initialize starting point of chart in the first column)
 NB. is this the first entry?
 if. (1 = nFirst) do.

   nFirst=. 0    NB. turn off flag to guarantee this is done only once:

   if. nClose >= ((nHigh - nLow) % 2) do.
     nColType=. nXCol
     nBoxHigh=. <. (nLow % nBox)
     nNewHigh=. <. (nHigh % nBox)
     for_b. i.((nNewHigh-nBoxHigh)+1) do.
       sChart=. 'X' (< (nBoxHigh+b+nRowOffset),nCurrCol) } sChart
     end.
   else.
     nColType=. nOCol
     nBoxLow=. <. (nHigh % nBox)
     nNewLow=. <. (nLow % nBox)
     for_b. i.((nBoxLow-nNewLow)+1) do.
       sChart=. 'O' (< ((nBoxLow-b)+nRowOffset),nCurrCol) } sChart
     end.
   end.
   if. 1 = nShowDate do.
     if. (0 = (sLastYearPlotted -: sYr)) do.
       for_c. i._4 do.
         sChart=. (c{sYr) (< (3-c),nCurrCol) } sChart
       end.
       sLastYearPlotted=. sYr
     end.
   end.

 else.    NB. the following is the normal (i.e., non-first) procedure:

   NB. convert prices to boxes:
   nNewHigh=. <. (nHigh % nBox)
   nNewLow=. <. (nLow % nBox)

   NB. continue upward direction?
   if. (nXCol = nColType) do.

     if. (1 <: (nNewHigh-nBoxHigh)) do.

       for_b. (1+i.(nNewHigh-nBoxHigh)) do.
         sChart=. 'X' (< (nBoxHigh+b+nRowOffset),nCurrCol) } sChart
       end.
       if. 1 = nShowDate do.
         if. (0 = (sLastMonthPlotted -: sMonth)) do.
           sChart=. sMonth (< (nBoxHigh+1+nRowOffset),nCurrCol) }sChart
           sLastMonthPlotted=. sMonth
           if. 1 = ".sMonth do.
             if. (0 = (sLastYearPlotted -: sYr)) do.
               for_c. i._4 do.
                 sChart=. (c{sYr) (< (3-c),nCurrCol) } sChart
               end.
               sLastYearPlotted=. sYr
             end.
           end.
         end.
       end.
       nBoxHigh=. nNewHigh
       nBoxLow=. nBoxHigh - 1    NB. for drawing purposes, 1 box below highest 'X'

     NB. no new high, so test for downside reversal:
     elseif. (nRevBoxes <: (nBoxHigh - nNewLow) ) do.

       if. (nCurrCol < nMaxColumns-1) do.
         nCurrCol=. nCurrCol + 1
       else.
         sChart=. |. sChart
         return.
       end.
       nColType=. nOCol
       for_b. i.((nBoxLow-nNewLow)+1) do.
         sChart=. 'O' (< ((nBoxLow-b)+nRowOffset),nCurrCol) } sChart
       end.
       if. 1 = nShowDate do.
         if. (0 = (sLastMonthPlotted -: sMonth)) do.
           sChart=. sMonth (< ((nBoxLow-2)+nRowOffset),nCurrCol) } sChart
           sLastMonthPlotted=. sMonth
           if. 1 = ".sMonth do.
             if. (0 = (sLastYearPlotted -: sYr)) do.
               for_c. i._4 do.
                 sChart=. (c{sYr) (< (3-c),nCurrCol) } sChart
               end.
               sLastYearPlotted=. sYr
             end.
           end.
         end.
       end.
       nBoxLow=. nNewLow
       nBoxHigh=. nBoxLow + 1    NB. for drawing purposes, 1 box above lowest 'O'
     end.

   NB. continue downward direction?
   elseif. (nOCol = nColType) do.

     if. (1 <: (nBoxLow-nNewLow)) do.

       for_b. (1+i.(nBoxLow-nNewLow)) do.
         sChart=. 'O' (< ((nBoxLow-b)+nRowOffset),nCurrCol) } sChart
       end.
       if. 1 = nShowDate do.
         if. (0 = (sLastMonthPlotted -: sMonth)) do.
           sChart=. sMonth (< ((nBoxLow-1)+nRowOffset),nCurrCol) } sChart
           sLastMonthPlotted=. sMonth
           if. 1 = ".sMonth do.
             if. (0 = (sLastYearPlotted -: sYr)) do.
               for_c. i._4 do.
                 sChart=. (c{sYr) (< (3-c),nCurrCol) } sChart
               end.
               sLastYearPlotted=. sYr
             end.
           end.
         end.
       end.
       nBoxLow=. nNewLow
       nBoxHigh=. nBoxLow + 1    NB. for drawing purposes, 1 box above lowest 'O'

     NB. no new low, so test for upside reversal:
     elseif. (nRevBoxes <: (nNewHigh - nBoxLow) ) do.

       if. (nCurrCol < nMaxColumns-1) do.
         nCurrCol=. nCurrCol + 1
       else.
         sChart=. |. sChart
         return.
       end.
       nColType=. nXCol
       for_b. i.((nNewHigh-nBoxHigh)+1) do.
         sChart=. 'X' (< (nBoxHigh+b+nRowOffset),nCurrCol) } sChart
       end.
       if. 1 = nShowDate do.
         if. (0 = (sLastMonthPlotted -: sMonth)) do.
           sChart=. sMonth (< (nBoxHigh+2+nRowOffset),nCurrCol) } sChart
           sLastMonthPlotted=. sMonth
           if. 1 = ".sMonth do.
             if. (0 = (sLastYearPlotted -: sYr)) do.
               for_c. i._4 do.
                 sChart=. (c{sYr) (< (3-c),nCurrCol) } sChart
               end.
               sLastYearPlotted=. sYr
             end.
           end.
         end.
       end.
       nBoxHigh=. nNewHigh
       nBoxLow=. nBoxHigh - 1    NB. for drawing purposes, 1 box below highest 'X'
     end.
   end.
 end.
end.  NB. "for" loop

NB. flip chart array so that smallest coords are at lower left
NB. rather than at upper left:
sChart=. |. sChart
)