F# how to rewrite C# event subscribe functions

Category: visual studio fsharp

Question

zydjohn on Wed, 18 Oct 2017 21:18:18


Hello:

I try to port some C# code into F#.  Someone has shown the following C# code to subscribe a stock price data service.  But the details are buried in a DLL file.  The following is the code:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using STOCKSDK;

using System.Runtime.InteropServices;

namespace test_md

{

    class Program

    {

        static void on_tick( Tick tick)

        {

            System.Console.WriteLine(string.Format("{0}  {1}.{2} {3}", tick.strtime, tick.exchange , tick.sec_id , tick.last_price));

        }

        static void on_bar(Bar bar)

        {

            System.Console.WriteLine(string.Format("{0}  {1}.{2} {3}", bar.strtime, bar.exchange , bar.sec_id , bar.close));

        }

        static void Main(string[] args)

        {

            MdApi md = MdApi.Instance;

            md.TickEvent += Program.on_tick;

            md.BarEvent += Program.on_bar;

            string v = md.Version();

            string e = md.StrError(1004);

            int ret = md.Init("UserID", "Password", MODE_PLAYBACK, "StockA.bar.daily", "2017-02-01 09:30:00", "2017-02-28 10:00:00");

            if(ret != 0)

            {

               System.Console.WriteLine("Login Failed");

                return;

            }

            md.Run();

            System.Console.Read();

        }

    }

}

From object viewer for STOCKSDK, I can see public class MdApi has one property: public static STOCKSDK.MdApi Instance { get; }; this class has 5 different events:

public event STOCKSDK.MDBarCallback BarEvent  Member of STOCKSDK.MdApi

public event STOCKSDK.MDErrorCallback ErrorEvent Member of STOCKSDK.MdApi

public event STOCKSDK.MDLoginCallback LoginEvent Member of STOCKSDK.MdApi

public event STOCKSDK.MDEventCallback MdEvent Member of STOCKSDK.MdApi

public event STOCKSDK.MDTickCallback TickEvent Member of STOCKSDK.MdApi

The Bar has the following definition in Object viewer: public Bar() Member of STOCKSDK.Bar

Bar has some members, like:

public string strtime Member of STOCKSDK.Bar

public string exchange Member of STOCKSDK.Bar

public string sec_id Member of STOCKSDK.Bar

public float close Member of STOCKSDK.Bar

The Tick has the following definition in Object viewer: public Tick() Member of STOCKSDK.Tick

Tick has some members, like:

public string strtime Member of STOCKSDK.Tick

public string exchange Member of STOCKSDK.Tick

public string sec_id Member of STOCKSDK.Tick

public float last_price Member of STOCKSDK.Tick

The Run method has the following signature: public int Run() Member of SOTCKSDK.MdApi

I understand the logical is like this: it first create an instance of MdApi, then subscribe to the Bar and Tick event, as long as the Bar and Tick event fires, call the event handler to print the necessary price information.

However, I cant figure out how to rewrite the above C# code in F#, the following is my code:

#light

open STOCKSDK

open System

open System.Collections.Generic

open System.Linq

open System.Text

open System.Threading

open System.Runtime.InteropServices

let on_tick(tick: Tick) =

printfn "%s %s %s %1.2f" tick.strtime tick.exchange tick.sec_id tick.last_price

let on_bar(bar: Bar) =

printfn "%s %s %s %1.2f" bar.strtime bar.exchange bar.sec_id bar.close

[<EntryPoint>]

let main args =

    let md = MdApi.Instance

    md.add_TickEvent += on_tick

    md.add_BarEvent += on_bar

    let v = md.Version()

    let e = md.StrError(1004)

let ret = md.Init("UserID", "Password", MODE_PLAYBACK, "StockA.bar.daily", "2017-02-01 09:30:00", "2017-02-28 10:00:00")

if (ret <> 0) then

       printfn "Login failed!"

    md.Run()

    printfn "Done!"

    0

The error messages are for the 2 lines:

    md.add_TickEvent += on_tick

    md.add_BarEvent += on_bar

Error FS0043 Expecting a type supporting the operator '+=' but given a function type. You may be missing an argument to a function.

In F#, when I typed md. I can see it has add_TickEvent; add_BarEvent; add_ErrorEvent; add_LoginEvent; add_MdEvent.  But I have no idea how to rewrite the code in C# for this two lines:

            md.TickEvent += Program.on_tick;

            md.BarEvent += Program.on_bar;

Thanks for your advices.

Replies

Mr. Tines on Wed, 18 Oct 2017 22:49:38


The simplest translation of a C# event subscription like

md.TickEvent += Program.on_tick;

would be

md.TickEvent.AddHandler Program.on_tick

or you could also write

md.TickEvent
|> Event.add Program.on_tick

zydjohn on Thu, 19 Oct 2017 07:45:45


Dear Mr. Tines:

Thank you very much for your reply.  However, the SDK seems to be not F# friendly.  I am using Visual Studio 2017. 

If I create a C# project, then in IDE, when I typed md.

Then I can see all events.  Look at the picture. 

But if I create a F# project, then in IDE, when I typed md.

Then I can only see the add_XXXevent; see the picture again; there is no such events available as in C#.

Therefore, it is impossible to use the codes you provided.

Their SDK support 5 programming languages: C/C++; C#; Matlab; Python; GNU R.  Unfortunately, F# is not supported.

If interested, you can download their SDK from this web site: http://www.myquant.cn/downloads/

The web site has some Chinese explanations, just ignore them, to download C# SDK, you can simply click on the Windows Icon besides the C# language (语言)

Unzip the downloaded file, there are 4 C# examples, in C# everything looks well.  But when I tried to use the SDK in F#, the events functions really did NOT work; but the other functions seem to be working in F#, as long as they don’t need event functions.  But the event functions are the most important functions in the SDK, since all the stock price subscriptions need the events to work.

Thanks again for your help.

Have a nice day!

Mr. Tines on Thu, 19 Oct 2017 15:18:23


Prompted by this hover-text message

this is what ended up building for me

open GMSDK

let on_tick(tick: Tick) =
  printfn "%s %s %s %1.2f" tick.strtime tick.exchange tick.sec_id tick.last_price

let on_bar(bar: Bar) =
  printfn "%s %s %s %1.2f" bar.strtime bar.exchange bar.sec_id bar.close

[<EntryPoint>]
let main args =
    let md = MdApi.Instance
    md.add_TickEvent (fun x -> on_tick x)
    md.add_BarEvent (fun x -> on_bar x)
    let v = md.Version()
    let e = md.StrError(1004)
    let ret = md.Init("UserID", "Password", MDMode.MD_MODE_PLAYBACK, "StockA.bar.daily", "2017-02-01 09:30:00", "2017-02-28 10:00:00")
    if (ret <> 0) then
       printfn "Login failed!"
   
    md.Run() |> ignore
    printfn "Done!"
    0

It needs to be a lambda so it gets automatically converted to a delegate type, even if usually this sort of lambda would want to be refactored to a direct function call.


zydjohn on Thu, 19 Oct 2017 19:45:49


Dear Mr. Tines:

Thank you very much for your code, your code get compiled, but when running, there was no results.  Even the C# code did NOT generate any results.  It could mean something wrong with their stock server.  I asked the technical support, hope they can help me to debug the C# code, if C# code works, I think F# code should also work.

Thanks and have a nice day!

zydjohn on Fri, 20 Oct 2017 09:12:06


Dear Mr. Tines:

Thanks, the technical support fixed the issue, it works now.

However, I can't see the hover-text message which you showed here.

In VS 2017, when I hover the md., I can only see:

MdApi.add_BarEvent(value: MDBarCallback): unit

Let me know how you can find the other information.

Thanks and have a nice day!

John

Mr. Tines on Sat, 21 Oct 2017 15:41:19


I was using VS2017 15.4.1, and I got that message when I'd put in the original code from your first post

    md.TickEvent += Program.on_tick;
    md.BarEvent += Program.on_bar;

and got a red squiggly underline.  I worked through to

    md.add_TickEvent (fun x -> on_tick x)
    md.add_BarEvent (fun x -> on_bar x)

which compiled, and then to take the picture, just backed off to

    md.TickEvent (fun x -> on_tick x)
    md.add_BarEvent (fun x -> on_bar x)
to get back to a state where I could get the interesting message. 


zydjohn on Mon, 06 Nov 2017 09:17:35


Thank you very much for your advice.

However, when I used VS2017 15.4; the debug function seems gone, I can't run any program in debug mode; so I went back to VS2017 15.3.

Hope I can go to next version of VS2017 where I can run program in debug mode.

I will try to figure out your way to find the solution.

Thanks again!