Articles

Free Download More Info
Here are some articles about developing for Personal Stock Streamer.

You can rss.gif subscribe to this feed with an RSS reader.
  • Developing a Trailing Stop Alert Extension
    10/11/2005 10:54AM

    Over the years we have been asked for a way to set trailing stop alerts on your stocks. It is a feature we always wanted to provide, but the software was not ready for it. Now with Personal Stock Streamer 7 extensions, the system can be written much easier and in a much more powerful and flexible way than would have been possible before.

    In general there are a number of techniques for setting trailing stops, but for this example we will use the simplest stop loss strategy:

    • At the moment the trailing stop is set, the high water mark is calculated as the higher of the purchase price and the most recent trading price.
    • When the ticker is updated, compare the current stock price to the high water mark.  If the stock price is higher, then adjust the high water mark upward.  If the stock price is lower by the set percentage (default 20%), raise an alert.

    Implementing more complicated trailing stop techniques is left as an exercise for the reader.  Of course we appreciate all contributions.  :-)

     

    In order to make the extension fairly efficient, we will use the custom attribute support in the scripting object model to keep track of several values that we need.  This will prevent unnecessary recalculations.
    • _TrailingStopMark attribute is the current high water mark.
    • _TrailingStopPct attribute is the threshold percentage.
    • _TrailingStopAlertAction attribute is the name of the alert action to run when the ticker hits the threshold.
    • _TrailingStopMemo attribute is a string that shows the stop mark and percentage in one string.  This is used as the visual feedback for display in the Trailing Stop column.

    It is important to note that we will use the new custom column support in Personal Stock Streamer 7.1 to create the Trailing Stop column.  This column is created by the extension but is not enabled in the view by default, so if you want to see whether a trailing stop is set for a ticker you will need to manually enable this column.

    As with previous extensions, this extension will repeat the familiar pattern of having a handler class with several functions to handler the various events from the application, followed by initialization code that runs when the extension is loaded.  During initialization we have to perform several tasks:

    • Create an instance of the handler class, and register it as the target for the application events we want to respond to.
    • Add two menu items to the Tools menu that allows users to set and clear trailing stops for a ticker.
    • Create a custom column for visual feedback so that users can see which tickers have a trailing stop set.

    The initialization code is fairly straightforward so there is no reason to cover it in this article.  Look at the source code for details.

    The handler class is a little more complicated.  When the user selects to set a trailing stop, the handler must ask the user for some additional parameters (such as the stop percentage and alert action).  The only way to do this within the script object model is to display an HTML form in a small window and handle the form submit event in our handler to read those parameters back.  This means that the actual setting of the trailing stop can not be done in the menu handler.  The only real tricky part in this section is that in order to get the form to post correctly back to our class, we must set the form method as "post" and the target as "x".  This little trick is necessary because of how our particular HTML browser control works.

    Set selectedTickers = Application.ActiveDocument.Selection.Tickers

    If (selectedTickers.Count > 0) Then
        Set wndManager = Application.GetObject("WindowManager")
        Set wndBrowser = wndManager.CreateBrowserWindow(300, 140, me)

        ...

        form = "<body bgcolor=white><form name=form1 method=post target=" + Chr(34) + "x" + Chr(34) + ">"

        ...

        form = form + "</form></body>"

        wndBrowser.SetHTML(form)
        wndBrowser.Title = "Set Trailing Stop"

    Note that when we create the browser window above, we set "me" as the handler object.  This means that when the user clicks the OK button to submit the form we must handle the response in the OnFormSubmitted method, which is where we can pull the parameters and set the trailing stops for the selected tickers.

    public Function OnFormSubmitted ( form )
        If (form.Value("submit") = "OK") Then
            SetMarks form.Value("pct"), form.Value("act")
        End If

        ... 

    The SetMarks function does most of the work of setting the trailing stops.  It iterates through the selected tickers, gets the default stop mark for each one (which is automatically calculated from the last purchase price or last trading price) and sets the properties.  Since the high water mark is calculated automatically, a future enhancement to this extension would be to allow the user to override this value in case a different high water mark is desired.

    The work of checking the high water mark is done in the OnTickerUpdated method of the handler class.  Since this method is called for every ticker that is updated, the first thing we must do is check whether a trailing stop is set for the ticker.  Since the GetProperty call will fail if the custom attributes have not been set for this ticker, we must make sure to set the error handling appropriately so that our script will not fail.

    dStopMark = 0
    dStopPct = 0

    On Error Resume Next
    dStopMark = CDbl(ticker.GetProperty("_TrailingStopMark"))
    dStopPct = CDbl(ticker.GetProperty("_TrailingStopPct"))
    On Error Goto 0

    At this point, if the dStopMark and dStopPct variables are non-zero, then a trailing stop has been set for the ticker.  Now what we need to do is get the current price of the ticker and compare it to the high water mark.  If it is higher, we move the high water mark, and if it is lower then we calculate the percentage difference and compare it to the threshold value.  We generate the alert only if the threshold has been reached.

    dPrice = ticker.GetProperty("Price")

    If (dPrice > dStopMark) Then
        dStopMark = dPrice
        
        ticker.SetProperty "_TrailingStopMark", dStopMark
        ...
     Else
        dDiffPct = ((dStopMark - dPrice) / dStopMark) * 100
       
        If (dDiffPct >= dStopPct) Then
            RunAlertAction ticker.GetProperty("_TrailingStopAlertAction"), ticker
        End If
    End If

    The RunAlertAction method does the work of actually firing the alert, which involves looking up the desired alert action and running it through the alert manager.

    Set manager = Application.GetObject("AlertManager")

    If Not manager Is Nothing Then
        For Each action in manager.Actions
            If action.GetProperty("Name") = name Then
                action.Run2 ticker, "Trailing Stop"
                Exit For
            End If
        Next
    End If

    Note that we use the new Run2 method of the alert action object, which allows us to specify the attribute to which the alert is related and will cause the little yellow alert bell to be displayed in the Trailing Stop column as visual feedback that the trailing stop alert has fired.

    The full source of the Trailing Stop extension is available here.

  • How to Create Scriptable Custom Columns
    07/27/2005 3:28PM

    One of the new features added in Personal Stock Streamer 7.1 is the ability to have custom columns in the Active Securities view, including scriptable columns.  In this article I will discuss how to create and manage scriptable columns. To learn about custom columns in general, read the section in the Personal Stock Streamer User's Guide as well as this article.

    The new script object that controls the custom columns is the ViewManager object.

    Set ViewManager = Application.GetObject("ViewManager")

    At this point you can create your custom columns.  Expression columns are very straightforward.  For example, if you wanted to create a column that always showed double the current price:

    ViewManager.CreateExpressionColumn "DoublePrice", "Price * 2"

    You could have just as easily added this column through the Custom Columns interface in the program preferences.

    The way scriptable columns work are a little more complicated, because scriptable columns are actually memo columns that get their value from a custom ticker attribute.  (To learn more about custom attributes, see the scripting object model documentation for the Ticker object.) This means that the value of scriptable columns is filled in indirectly, and you must do the work yourself to fill in the custom attribute and update the view.  The reason it was done this way is to make the custom column processing more efficient by avoiding having to recalculate the column value every time the ticker was updated, leaving your script in full control over the timing of the updates.

    So to start, let's create a custom column that is associated with a custom attribute.  This example is taken from the Trailing Stop extension.

    ViewManager.CreateMemoColumn "Trailing Stop", "_TrailingStopComment", True

    This code creates a memo column called "Trailing Stop" that gets its value from the _TrailingStopComment attribute, and is read-only in the Active Securities view so the user can not edit it.  How do we fill in the _TrailingStopComment variable?  The answer to this is inside the Trailing Stop extension: the _TrailingStopComment attribute is set when the trailing stop is set on the ticker, or when the high water mark is updated.  The code is as follows:

    tmp = FormatNumber(CDbl(dStopMark), 2) + ", " + FormatNumber(CDbl(dStopPct), 2) + "%"
    ticker.SetProperty "_TrailingStopComment", tmp

    The last thing that needs to be done is that the user interface needs to be updated in order to show the new value for this column:

    Set ViewManager = Application.GetObject("ViewManager")
    ViewManager.UpdateObjectInView(ticker)

    This design ensures that the user interface is only updated when necessary, preventing unnecessary running of script code.

    With this basic code it is possible to create columns whose value is calculated through script, which allows you to go through your portfolio and do things like calculations based on historical data or relative to another ticker in the portfolio.  If you are interested in creating your own scriptable columns, I recommend reading our Personal Stock Streamer object model documentation and samples found on the Developers section of this site.  Also, the full source code for the Trailing Stop extension is available here.

     

  • Introduction to Personal Stock Streamer Extensions
    03/31/2005 11:31PM

    Introduction

    For a long time we have received requests for features and extensions that we could not easily provide with our limited development resources. As a micro-corp we must focus on providing the most value possible for the largest number of customers, so many requests stayed on our to-do lists for quite a long time. Previous versions of Personal Stock Streamer included a way to extend the software with plug-ins, but writing plug-ins required advanced programming knowledge and was therefore out of the reach of most of our customers.

    With the Personal Stock Streamer 7.0 release, we have now included a way for our customers to easily extend the software on their own through scripting. Because writing extensions is now so much easier than before, we at DTLink Software are also considering offering custom extension writing services for our customers who are interested in specific functionality.

    What is Possible

    Personal Stock Streamer extensions can be written with any of a number of scripting languages, including VBScript, JScript, PerlScript, and Python. In all cases the object model will be the same. The same object model can also be accessed from other OLE-compatible applications such as Excel, which allows for extensive custom integration, but that is a topic for another article.

    The object model includes access to all of your portfolio data, including multiple portfolios, tickers, transations, alerts, and historical data. It includes the ability to add custom menus commands to the application and receive events when those menu commands are selected. It includes the ability to define custom technical indicators for the charts, the ability to create custom reports, the ability to generate alerts, and more. Detailed object model documentation is available on the Personal Stock Streamer web site.

    Scripts vs. Extensions

    Personal Stock Streamer can run simple standalone scripts, and specially formatted scripts can be installed as extensions. When scripts are installed as extensions, they are automatically loaded when Personal Stock Streamer starts. This allows them to do things such as installing event handlers that would otherwise not be possible in regular scripts.

    How Extensions Work

    In order for your script extensions to be loaded when Personal Stock Streamer starts, two things must happen. First, they must be wrapped in a simple XML document; second, they must be installed through the extension installer interface under the Tools menu.

    The XML wrapper looks like this:

    <pss_extension name="Hello World Sample" version="1.0">Sample Hello World Extension
    <author email="support@dtlink.com" name="DTLink Software" url="http://www.dtlink.com" />
    <script language="VBScript">
    <![CDATA[
    *** your script code goes here ***
    ]]>
    </script>
    </pss_extension>
    <signature>
    optional digital signature
    </signature>

    The XML wrapper briefly describes the extension in the installer interface and identifies you as the author. The extension code becomes part of a CDATA node in order to prevent the XML parser from interpreting tags incorrectly. The only restriction is that your script must not contain the "]]>" string that ends the CDATA nodes.

    Extensions can optionally digitally signed in order to verify their authenticity for users. Personal Stock Streamer will test the extension signature before it is installed and will warn the user if there is no digital signature or if it does not match the extension. Oh the other hand, signed extensions will present with a nice dialog containing information about you and the extension. In either case the user will decide whether to allow the extension to be installed.

    Once the extensions are installed, any code that is at the global scope of the script will be run when the extension is loaded at program startup. This part of the code will normally consist of initialization code that registers the necessary objects and event handlers with the host application.

    Creating a Basic Extension

    Before creating a basic extension I would recommend reviewing the Personal Stock Streamer object model documentation on the web site. Becoming familiar with this object model will make following the rest of this article much easire.

    For this example we will create a basic extension that adds a menu item to the Tools menu and displays a message box when the menu is pressed. This requires us to define a class to be the menu event handler and register it with the application.

    So let's start with a basic class to handle a menu event. If you have read the object model documentation you know that the menu handler is called OnMenuItemSelected(), so we start with this:

    class HelloWorldHandlerClass

        ' menu event handler
        public Function OnMenuItemSelected ( id )

            If (id = menuId) Then
                MsgBox "Hello, World", vbOKOnly

                ' set return value to indicate that menu selection was processed
                OnMenuItemSelected = True
            End If

        end Function

        Dim menuId

    end Class

    Now we have a class that we can use as a menu handler. Because there may be other extensions registered, we must first check whether the menu id matches our menu.

    The next step is to register our handler class with the host application:

    ' get our event objects
    Set EventManager = Application.GetObject("EventManager")
    Set MenuManager = Application.GetObject("MenuManager")
    Set Handler = new TestHandlerClass

    ' create the menu item
    If Not MenuManager Is Nothing Then

        ' find the tools menu
        Set MainMenu = MenuManager.MainMenu
        Set ToolMenu = MainMenu.GetSubMenu(MainMenu.Find("Tools"))

             ' insert our menu item
        If Not ToolMenu Is Nothing Then
            Handler.menuId = ToolMenu.InsertItem(ToolMenu.ItemCount, "Hello World")
        End If
    End If

    ' register the menu handler
    If Not EventManager Is Nothing Then
        EventManager.RegisterHandlerMethod Handler, "OnMenuItemSelected"
    End If

    This section of code does a few things that are necessary for this extension to work. First, it gets references to the application objects and creates an instance of our menu handler object. Second, it finds the Tools menu and inserts the menu item. Note how the code saves the menu id of the menu item we created in the handler class. All of this should be pretty straighforward if you're familiar with Visual Basic or VBScript.

    Lastly, we just need to create the XML wrapper for this extension like I showed above so that the extension can be installed properly. The completed extension is available here.

    Finishing Up

    Testing your extension is a matter of installing it under Personal Stock Streamer using the Extensions manager under the Tools menu. Extension management is based on version number, so once an extension is installed it can easily be updated in-place as long as don't move the xml file.