alexliou 發表於 17-4-24 10:32

群益API 2.13.5 C#實作

本帖最後由 alexliou 於 17-4-24 11:29 編輯

我以群益API元件(2.13.5) 所附的C#範例檔為藍本寫了一個輕量型的看盤下單 Application




與群益的C#範例檔相較, 它有以下一些不同的features :
1. 一執行就開始自動登入與連線, 不用user 去 click button(當然, 第一次執行時還是要去設定帳號).
2. 限價單與停損單下單使用同一個介面.
3. 下單(與取消)是否成功有人聲提醒, 並自動顯示於委託簿.
4. 委託簿中未成交委託列前會顯示"刪"字, 按兩下即可刪單.
5. 成交時會有人聲提醒,並會自動更新部位狀況與帳戶權益.
6. 報價部分可設定十組自選股組合以供選擇
7. 在自選股組合中單一股票的股號上按兩下即可顯示該股的五檔報價與Tick明細,
或User可於 combobox中自行選取.
8. 為避免傳送 Historical Ticks時, 一次傳遞極大量的量Ticks造成其它UI的反應緩慢, 顯示Ticks的
datagridview 採用virtual mode.

Possible furthur steps:
1. 本程式沿襲了群益範例的做法, 將下單與報價放在不同的Tabpage, 且使用兩個User Control 來implement,
這可能是一個架構上的缺陷, 這不合一般使用者的習慣, 因為大部分的使用者是眼睛看著報價下單的,
把報價和下單在同一個頁面上對User比較方便.
2. 下單目前僅限於大台當月契約與小台當月契約, 可將範圍擴大.
3. 表單右方目前是一個顯示訊息的ListBox, 這對developer 去了解程式與API元件的反應相當有用,
但對最終目的(下單或看盤)完全沒有效用, 而且API元件會自動寫Log, 這個ListBox可以拿掉, 把版面用來
implement 一個閃電下單介面(像Multicharts DOM Trading的介面是個不錯的選項).
4. 顯示Ticks的datagridview雖然設定為virtual mode, 但可顯示列數是變動的,如能設為不超過1000的定值,
可能performance會更好,但需要更多的programming efforts.
(如果盤中經常切換標的, 且不需要過去的Tick紀錄, 可unsubscribe OnNotifyHistoricalTicks Event)
5.........
附件為附原始碼的Visual Studio Solution 壓縮檔








alexliou 發表於 17-4-24 19:56

本帖最後由 alexliou 於 17-4-24 20:06 編輯

Possible further steps:......4. 顯示Ticks的datagridview雖然設定為virtual mode, 但可顯示列數是變動的,如能設為不超過1000的定值,可能performance會更好,但需要更多的programming efforts.=====>
4. 程式中使用了許多datagridview來做為顯示報價的 user interface, 同時也使用了許多CellFormatting routines 來做資料格式化的工作. 這些routines 都還沒有最佳化, 效率仍有待提升.

alexliou 發表於 17-4-26 09:47

有download下去玩的版友可能會發現
在開盤一段時間後,switch 五檔及Tick明細時, response 會越變越慢
可修改ReceiveTicks Method, 增加以下紅字粗體部分的code
效率會提升很多喔

private void ReceiveTicks(short sMarketNo, short sStockIdx, int nPtr, int nTimehms, int nTimemillismicros, int nBid,
         int nAsk, int nClose, int nQty, int nSimulate)
      {
            PutToTicksTable(sMarketNo, sStockIdx, nPtr, nTimehms, nTimemillismicros, nBid, nAsk, nClose, nQty, nSimulate);
          if (nPtr>=firstTick)
                TicksGrid.RowCount = TicksTable.Rows.Count;         
      }


alexliou 發表於 17-5-1 15:18

chang91348 發表於 17-5-1 13:59
照說明書似乎是如此,可是新版的API把requestTicks 的PageNo 直接設為0,而我也不知道要如何讓二個PageNo,可 ...

OnNotifyTicks() 雖然並未傳回是用哪個pageNo Request的
但它的參數中有個 sIndex 可用來辨別所傳回的Tick 是屬於哪支股票的
只是它有點間接, 因為Request時是用 stockNo, 接收時卻變成sIndex
這兩者之間的關係需靠GetStockByNo() 回傳的SKSTOCK物件才可得知

Tick有沒有變動, 我們無法主動得知, 只能等Server通知
OnNotifyTick 就是Server主動告知Tick 發生變動的事件
如果User 想要主動用GetStockByNo()去拿Tick
會面臨以下的問題:
1. 要多久去Get一次?
2. 這次的Get跟上一次的Get, 中間可能會漏Tick, 或是沒有新Tick
所以, 如要完整地接收Ticks, 只能靠OnNotifyTick()
如果只是需要某些特定時點的snapshot, GetStockByNo可能可以滿足需求

OnNotifyTick() 的功能就像 你所提的WorkSheets_Change
是一個Event, Server端利用它來通知Tick發生變動了
OnNotifyTick()的參數 其實是EventArg
Server端把要傳遞的訊息利用這些參數傳回給client program





lawlu 發表於 18-4-15 20:23

感謝Alex大的提點

報價已經可以顯示在datagridview上了,但是目前遇到無法下單成功的狀況,我是參考群益的excel 範例及C#的範例-StockOrderControl.cs的寫法而去修改的,程式碼如下,可否請Alex大大在幫忙看一下哪裡有錯,再次感謝!!

    Private Sub skO_OnAccount(bstrLogInID As String, bstrAccountData As String) Handles skO.OnAccount

      Dim strValues As String()
      Dim strAccount As String
      strValues = bstrAccountData.Split(","c)
      strAccount = bstrLogInID & " " & strValues(1) & strValues(3)
      If strValues(0) = "TS" Then
            boxStockAccount.Items.Add(strAccount)
      End If

    End Sub

    Private Function SendStockOrder(ByVal bAsyncOrder As Boolean)

      Dim strInfo As String = boxStockAccount.Text
      Dim strValues As String()

      strValues = strInfo.Split(" "c)
      UserAccount = strValues(1)
      lbxR.Items.Add(strValues(1))

      Dim strStockNo As String
      Dim nPrime As Integer
      Dim nBidAsk As Integer
      Dim nPeriod As Integer
      Dim nFlag As Integer
      Dim strPrice As String
      Dim nQty As Integer

      strStockNo = txtStockNo.Text.Trim()
      nBidAsk = boxBidAsk.SelectedIndex
      nFlag = boxFlag.SelectedIndex
      strPrice = txtPrice.Text.Trim()
      nQty = txtQty.Text
      nPrime = 0
      nPeriod = 0


      Dim pOrder As SKCOMLib.STOCKORDER = New SKCOMLib.STOCKORDER()

      pOrder.bstrFullAccount = UserAccount
      pOrder.bstrStockNo = strStockNo
      pOrder.sBuySell = CShort(nBidAsk)
      pOrder.sFlag = CShort(nFlag)
      pOrder.sPrime = nPrime
      pOrder.sPeriod = nPeriod
      pOrder.bstrPrice = strPrice
      pOrder.nQty = nQty

    End Function

    Private Sub btnSendStockOrderAsync_Click(sender As Object, e As EventArgs) Handles btnSendStockOrderAsync.Click

      SendStockOrder(True)

    End Sub

alexliou 發表於 17-5-8 09:57

stock1586 發表於 17-5-7 12:03
請問大大可以與你討論自製的看盤介面跟下單介面?
是否ˇ可以請教你

no problem, 請隨便問

youhap 發表於 17-4-24 12:08

感謝分享,最近也在研究群益API

chang91348 發表於 17-4-30 22:45

版主你好,我是從VBA跳來C# 的新手,因為金幣不夠,無法購買版主的檔案,真是對不住,有個問題想請教,因為在VBA有個WorkSheet_Change的方法,可以捕捉每一次儲存格變動的資料,轉來C# 之後,研究了許久,以海期為例,似乎是以 SKOSQuoteLib_RequestTicks來註册報價, 而由 OnNotifyTicks 來捕捉所註册檔案的報價回傳,但一個Page只能註册一檔,我是否可以另外自己再加入一個按鈕 btnTick2, 使用另一個 page No,如pageNo=2,再用SKOSQuoteLib_RequestTicks來註册報價,這樣群益是否就可以同時傳二檔報價的Tick? 如果不行的話,那是否要用SKOSQuoteLib_RequestStocks,來註册二檔,用GetStockByIndex來取得報價,只是不知道之後,要如何將每一檔變動的資料,分別儲存下來?還請賜教,謝謝

chang91348 發表於 17-5-1 12:57

RequestStocks是可註册50檔,但RequestTicks只能註册一檔,從OnNotifyTick我可以很容易拿到每筆成交資料,但卻只能拿到一檔,如果要拿到多檔,似乎只能從RequestStocks註册,從OnNotifyQuote拿到"即時"一個Tick的資料,可是我的能力尚淺,不知要用什麼方法,把這個每筆的即時Tick變動時,儲存起來,有像VBA有WorkSheets_Change的事件處理方法嗎?

chang91348 發表於 17-5-1 13:59

照說明書似乎是如此,可是新版的API把requestTicks 的PageNo 直接設為0,而我也不知道要如何讓二個PageNo,可以接收到二檔不同的報價(說實話,真的不知道是如何根據不同的PageNo接收不同的訊號,從程式內找不到這個方法,只是根據說明書,應是由OnNotifyTick接受,但裡面的參數没有PageNo這項,所以OnNotifyTick只是被動接收網路傳來的Tick,好像没法選擇是那個PageNo的訊息?)

chang91348 發表於 17-5-1 20:18

感謝版主的回覆,剛才嘗試了一下,果然可以得到二檔的Tick了,只是二檔的資料都混在一起了,確實是以版主所說的,是以SIndex來做區分,只是我的資質有限,無法體會版主如何使用GetStockByNo來知道那一檔是那一個SIndex,目前只有先註册一檔,先得到一個SIndex,然後再註册另一個,再得到它的SIndex,之後再根據SIndex把二檔分開,目前看來每檔的SIndex似乎是固定的,不知是否有更好的辦法?

alexliou 發表於 17-5-1 21:05

chang91348 發表於 17-5-1 20:18
感謝版主的回覆,剛才嘗試了一下,果然可以得到二檔的Tick了,只是二檔的資料都混在一起了,確實是以版主所說的 ...

GetStockByNo()中的byRef參數 SKStock struct 的第一個成員sStockidx 就是 sIndex

chang91348 發表於 17-5-2 13:41

再次感謝版主的回覆,說實話,還是不太清楚要如何拿到sIndex,目前金幣已夠,所以先購買版主的程式,也許看範例可以了解更多,謝謝

ethanliang 發表於 17-5-2 21:41

樓主您好:
我是使用 VB6 撰寫程式碼
在Module 中先定義
   Public Type SKTICK
      nPtr As Long
      nTimehms As Long         
      nTimemillismicros As Long   
      nBid As Long
      nAsk As Long
      nClose As Long
      nQty As Long
      nSimulate As Long   
   End Type

然後在 Form中,使用按鈕
On Error Resume Next
    Dim nCode As Integer
    Dim Tick As SKTICK
   Set SKQuote = New SKQuoteLib
   nCode = SKQuote.SKQuoteLib_RequestTicks(-1, "TX05")
   nCode = SKQuote.SKQuoteLib_GetTick(MarketNo, Index, Ptr, Tick)

在上面程式碼 nCode = SKQuote.SKQuoteLib_GetTick(MarketNo, Index, Ptr, Tick)
中的 Tick
卻出現 "編輯錯誤,ByRef 引數型態不符 " 的訊息 !

請問要如何修改,謝謝。

alexliou 發表於 17-5-3 05:22

ethanliang 發表於 17-5-2 21:41
樓主您好:
我是使用 VB6 撰寫程式碼
在Module 中先定義


Sorry, 原先給你的回答是錯的
忘了VB pass arguments by reference 只需要在 function declaration時 註明是ByRef
在function Invoke 時, 直接pass 參數就好, 不用在註明是 ByRef

看起來, 錯誤訊息 "ByRef 引數型態不符" 指的是 Tick並不是 SKQuote.SKQuoteLib_GetTick()所需要的參數型態

你在自己的 Module裡定義了一個SKTICK 型態
但在 SKCOMLIB裡也定義了一個SKTICK 型態 (structure)
SKQuote.SKQuoteLib_GetTick()所需要的參數型態是SKCOMLIB.SKTICK
你所定義的SKTICK Type 無法自動轉換為SKCOMLIB.SKTICK
把 Public Type SKTICK ...............End Type 這一段刪掉
錯誤訊息應該就會消失了


ethanliang 發表於 17-5-3 19:31

樓主您好:
我已經把在Module 中定義的
   Public Type SKTICK   .......   End Type刪除

然後在 Form中,使用按鈕
On Error Resume Next
    Dim nCode As Integer
    Dim Tick As SKCOMLIB.SKTICK
   Set SKQuote = New SKQuoteLib
   nCode = SKQuote.SKQuoteLib_RequestTicks(-1, "TX05")
   nCode = SKQuote.SKQuoteLib_GetTick(MarketNo, Index, Ptr, Tick)
執行結果是"VB6停止運作"
請問,Dim Tick As SKCOMLIB.SKTICK 這段程式碼要如何修正?


謝謝。

chang91348 發表於 17-5-3 20:17

感謝版主,經過測試,已可正確取得sStockidx了,這時才知道DDE掉Tick掉了一半..感恩
頁: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: 群益API 2.13.5 C#實作