Forum

Free Download More Info
Welcome to the Personal Stock Streamer Developers Forum. Anyone can read messages, but you must be a registered user in order to post. (Sorry, we did this in order to prevent forum spam.)

Everyone who is registered for the Developers Forum on this site should now also have permission to log in and post to the Support Forum.  This was done by hand, so we may have missed a couple of people.  Please let us know if you do not have access to both forums.
Subscribe to RSS Feed
PSS Developers Forum -> custom indicator
Not logged in.
\n\n \n\n\n");
2006-03-27 08:37:30
1 of 2
#672
hi, i'm trying to create a new custom indicator. i took the sample code for "price relative" indicator and modified it to perform the calculations. It kind of works, but it runs very, very slow. It takes minutes to complete the calculation in daily charts. PSS seems to update the indicator every few seconds which leads to long delays in application's responsivness. Maybe there's something fundamentally wrong (i'm at very early stages of learning this) with my approach?

The code follows:

<pre>
<pss_extension name="Fractal Dimension" version="1.0.20">Fractal Dimension
<author email="" name="" url="" />
<script language="VBScript">
<![CDATA[

class FractalDimensionIndicator

        dim y()
        dim n,d
        dim ymax, ymin
   dim reca
   
        public Function InitFD
           n = 1
                d = 0

                Redim y(0)
                y(0) = 0
      ymax = y(0)
                ymin = ymax

        End Function

        Public Function FD(price)
                 n = n+1
                 Redim y(n)
                 y(n) = price
                 If y(N) >= ymax THEN ymax = y(N)
                 If y(N) <= ymin THEN ymin = y(N)

                 If ymax-ymin <> 0 then
          LenCalc y, ymin, ymax, N, Length
                    if (2*(N - 1)) > 0 and length > 0 then D = 1 + Log(Length) / Log(2*(N - 1))
          'D = (d - Int(d))*100
                    FD=D
                 End If
        End Function

   ' ****** Len Calc; Subroutine that Calculates the Normalized Length of the Waveform
        public Function LenCalc (y(), ymin, ymax, N, Length)
                 Length = 0
                 FOR i = 1 TO N
                       yi = (y(i) - ymin) / (ymax - ymin)
                  IF (i > 1) THEN Length = Length + SQR((yi - yant) ^ 2 + (1 / (N - 1)) ^ 2)
                       yant = yi
                 NEXT
        END function ' ***** End of LenCalc *****


   ' create the chart
   public Function Create ( ChartObject )
      Set ChartManager = Application.GetObject("ChartManager")

      ' create the dataset
      Set MyDataSet = ChartObject.CreateObject("DataSet")
      MyDataSet.ID = "Fractal Dimension"
      MyDataSet.Color = "Black"
      MyDataSet.PenWidth = 2

      ChartObject.AddObject(MyDataSet)

      ' create a separate canvas, the background rectangle for the chart
      Set Canvas = ChartObject.CreateObject("Canvas")
      Canvas.ID = "Fractal Dimension"
      ChartObject.AddObject(Canvas)

      ' create a legend for this chart
      Set Legend = ChartObject.CreateObject("Legend")
      Canvas.AddObject(Legend)
      Legend.AddDataSet(MyDataSet)

      ' create the actual chart object, in this case a line chart
      Set LineChart = ChartObject.CreateObject("LineChart")
      Canvas.AddObject(LineChart)
      LineChart.ID = "Fractal Dimension"
      LineChart.AddDataSet(MyDataSet)

      ' create and add the chart frame
      Set Frame = ChartObject.CreateObject("Frame")
      Frame.SetRelativeObject(LineChart)
      Canvas.AddObject(Frame)

      ' create and add the axis
      Set YAxis = ChartObject.CreateObject("Axis")
      YAxis.TranslateReverse = true
      YAxis.LabelFormat = "%0.4lf"
      LineChart.SetAxis YAxis, "Right", false
      LineChart.AddObject(YAxis)

      Set XAxis = ChartObject.CreateObject("Axis")
      XAxis.TickSize = 0
      XAxis.MinorTickSize = 0
      XAxis.FontSize = 0
      LineChart.SetAxis XAxis, "Bottom", false
      LineChart.AddObject(XAxis)

      ' the Create function needs to return a reference to the chart object
      Set Create = LineChart
   end Function

   ' recalculate the indicator based on current settings
   public Function Recalc ( ChartObject )
           
      Set ChartManager = Application.GetObject("ChartManager")

      ' get the data sets to work with
      Set MyDataSet = ChartObject.GetDataSet("Fractal Dimension")
      Set CloseDataSet = ChartObject.GetDataSet("Close")
      Set DateDataSet = ChartObject.GetDataSet("Date")

      ' find the relative ticker requested by user
      Set Doc = Application.ActiveDocument
      Set AltTicker = Doc.FindTicker(Nothing, ChartObject.GetParam(0), 0)

      ' check if the ticker exists in the document
      If AltTicker Is Nothing Then
         ' if ticker was not found, create temporary ticker
         Set AltTicker = Doc.CreateTicker
         Set Portfolio = Doc.CurrentPortfolio

         If Not AltTicker Is Nothing Then
            AltTicker.SetProperty "Symbol", ChartObject.GetParam(0)
            AltTicker.SetProperty "Visible", "0"

            Portfolio.Insert -1, AltTicker

            ' set the label on this chart
            MyDataSet.Label = MyDataSet.ID + " (" + ChartObject.GetParam(0) + ") "

            ' make sure this ticker gets deleted when the chart is closed
            ChartObject.DeferDeleteTicker(AltTicker)
         End If
      End If

      ' now that we have a ticker, process the historical data
      If Not AltTicker Is Nothing Then
         Set AltCloseDataSet = ChartObject.GetDataSetFromTicker(AltTicker, "Close")
         LastValidAltCloseData = -1
         LastValidCloseData = -1

         ' make sure we generate the exact same amount of data as in the original data set
         MyDataSet.Size = CloseDataSet.Size

         ' check for a valid data set
         If AltCloseDataSet Is Nothing Then
            
            ' if there was no data set, set a dummy value so it will at least display the chart
            MyDataSet.Data(MyDataSet.Size - 1) = 0
            MyDataSet.Label = MyDataSet.ID + " (" + ChartObject.GetParam(0) + ") "

            ' request historical data from the application
            ChartObject.RequestHistoricalDataForTicker(AltTicker)
         Else
            ' loop through all of the data and calculate the indicator
            
            InitFD()
            
            'dim filesys, filetxt, getname, path
                                'Set filesys = CreateObject("Scripting.FileSystemObject")
                               ' Set filetxt = filesys.CreateTextFile("c:\sndk.txt", True)
                                'path = filesys.GetAbsolutePathName("c:\sndk.txt")
                               ' getname = filesys.GetFileName(path)
                                
                                            
            For x = 0 To CloseDataSet.Size - 1
               If (CloseDataSet.IsValidData(x) And CloseDataSet.Data(x) > 0) Then
                  LastValidCloseData = x
                                    
                                                        MyDataSet.Data(x) = FD(CloseDataSet.Data(x))
                          'filetxt.WriteLine(CloseDataSet.Data(x))

                  If (AltCloseDataSet.IsValidData(x) And AltCloseDataSet.Data(x) > 0) Then
                     LastValidAltCloseData = x

   
                     'MyDataSet.Data(x) = CloseDataSet.Data(x) 'CloseDataSet.Data(x) / AltCloseDataSet.Data(x)
                  End If
               End If
            Next
            
            'filetxt.Close

            ' set the label on this chart
            If (LastValidAltCloseData >= 0) Then
               MyDataSet.Label = MyDataSet.ID + " (" + ChartObject.GetParam(0) + ") " + FormatNumber(MyDataSet.Data(LastValidAltCloseData), 4)
            Else
               MyDataSet.Label = MyDataSet.ID + " (" + ChartObject.GetParam(0) + ") "
            End If
            
            ' check data at the end of the range
            If LastValidAltCloseData < LastValidCloseData - 2 Then
               ChartObject.RequestHistoricalDataForTicker(AltTicker)
            End If
         End If
      End If
   end Function

end Class

' ================================================

Set ChartManager = Application.GetObject("ChartManager")

If Not ChartManager Is Nothing Then
   Set MyIndicator = ChartManager.RegisterIndicator("Fractal Dimension")

   If IsObject(MyIndicator) And Not MyIndicator Is Nothing Then
      MyIndicator.ID = "Fractal Dimension"
      MyIndicator.Description = "Fractal_Dimension"
      MyIndicator.HandlerObject = new FractalDimensionIndicator
      MyIndicator.NumParameters = 1
      MyIndicator.DefaultParameters = ""
      MyIndicator.OverlaysAllowed = "SMA,EMA,T3,TEMA,DEMA,TRIMA,WMA"
      MyIndicator.AllowOnIntradayChart = True
   End If
End If

]]>
</script>
</pss_extension>
</pre>


Posted by: jmirra
2006-03-27 10:16:16
2 of 2
#674
in reply to #672
Yes, the charts are designed to update dynamically, so it does recalculate the indicator every few seconds. Perhaps we can add some option in a future release to tell the charts how often the indicator should be updated.


In any case, this is a pretty complex calculation that you're doing all in VBScript, which isn't a particularly fast language to begin with. It looks like for each data point it has to recalculate some values for all previous data points (for i = 1 to N) so for each iteration it actually takes longer than the previous iteration; if you have a lot of data points this is what really slows down the process. If there is a way to keep some array of precalculated values of previous data points so that you get rid of this (for i = 1 to N) loop, it will greatly speed up the calculation.
      
Anatoly Ivasyuk
DTLink Software

Anatoly Ivasyuk
DTLink Software