建議使用右側的「搜尋此網誌」與「標籤」來存取

2009年12月15日 星期二

[教學] 使用 C# 介接群益的報價 API (SKQuoteLib.dll)

啊...要先聲明的是,我的程式功力不是很好,所以就看看就好囉~~^^"

另外使用「Windows Form 應用程式」來建立專案的原因
其一是因為,需要有個 thread 一直活著,才能接收 call back
其二是因為,SKQuoteLib_GetStockByNo 的第一個參數 (字串)
我用盡能想到的字串型式,就是沒辦法正確讓 API 收到
但是用 windows form 的 Textbox.text 就可以 @@"

以下是片段的程式碼,出錯賠錢不要找我 = ="
然後我沒有做所有的部分,要參考的請注意!!
編號是我自己用來認知排序的,不然一堆字很難認....
而且這裡不太好排版跟上色,請見諒....

-----------------------------------------------------------------
using System.Runtime.InteropServices;

public partial class Form1 : Form
{
/*
* DLL Import:
* 0. SKQuoteLib_Initialize
* 1.0 SKQuoteLib_AttachConnectionCallBack
* 1.1 SKQuoteLib_AttachQuoteCallBack
* 1.2 SKQuoteLib_AttachTicksCallBack
* 1.3 SKQuoteLib_AttachBest5CallBack
* 2. SKQuoteLib_EnterMonitor
* 3. SKQuoteLib_GetStockByNo
* 4. SKQuoteLib_RequestTicks
* 5. SKQuoteLib_GetTick
* END. SKQuoteLib_LeaveMonitor
*/

// 0.初始使用者相關資訊
[DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall)]
extern static int SKQuoteLib_Initialize(String lpszLoginID, String lpszPassword);

// 1.0.向報價函式庫註冊接收連線狀態的 Call back 函式位址
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate void FOnNotifyConnection(Int32 nKind, Int32 nCode);
static FOnNotifyConnection Delegate_AttachConnection = new FOnNotifyConnection(CBFunc_AttachConnection);

[DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall)]
extern static int SKQuoteLib_AttachConnectionCallBack(FOnNotifyConnection Delegate_AttachConnection);

// 1.1.當有索取的個股報價異動時,將透過此註冊的函式通知應用程式處理
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate void FOnNotifyQuote(Int16 sMarketNo, Int16 sStockidx);
static FOnNotifyQuote Delegate_AttachQuote = new FOnNotifyQuote(CBFunc_AttachQuote);

[DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall)]
extern static int SKQuoteLib_AttachQuoteCallBack(FOnNotifyQuote Delegate_AttachQuote);

// 1.2.當有索取的個股成交明細有所異動,即透過向此註冊的 Call back 函式進行處理
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate void FOnNotifyTicks(Int16 sMarketNo, Int16 sStockidx, Int32 nPtr);
static FOnNotifyTicks Delegate_AttachTicks = new FOnNotifyTicks(CBFunc_AttachTicks);

[DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall)]
extern static int SKQuoteLib_AttachTicksCallBack(FOnNotifyTicks Delegate_AttachTicks);

// 1.3.當有索取的個股五檔價格有所異動,即透過向此註冊的Call back 函式進行處理
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate void FOnNotifyBest5(Int16 sMarketNo, Int16 sStockidx);
static FOnNotifyBest5 Delegate_AttachBest5 = new FOnNotifyBest5(CBFunc_AttachBest5);

[DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall)]
extern static int SKQuoteLib_AttachBest5CallBack(FOnNotifyBest5 Delegate_AttachBest5);

// 2.建立與報價伺服器的連線
[DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall)]
extern static int SKQuoteLib_EnterMonitor();

// 3.根據股票代號取得報價資訊
[DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
extern static int SKQuoteLib_GetStockByNo(String lpszStockNo, ref TStock pStock);

// 4.要求傳送成交明細以及五檔
[DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
extern static int SKQuoteLib_RequestTicks(ref Int16 psPageNo, String pStockNo);

// 5.取得成交明細資訊
[DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall)]
extern static int SKQuoteLib_GetTick(Int16 sMarketNo, Int16 sStockidx, Int32 nPtr, ref TTick pTick);

// END.中斷與報價伺服器的連線
[DllImport("SKQuoteLib.dll", CallingConvention = CallingConvention.StdCall)]
extern static int SKQuoteLib_LeaveMonitor();


/*
* Struct:
* TStock
* TTick
*/

// [struct] TStock
[StructLayout(LayoutKind.Sequential)]
public struct TStock
{
public Int16 m_sStockidx; // 系統自行定義的股票代碼
public Int16 m_sDecimal; // 報價小數位數
public Int16 m_sTypeNo; // 類股分類
public byte m_cMarketNo; // 市場代號0x00上市;0x01上櫃;0x02期貨;0x03選擇權;0x04興櫃
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public String m_caStockNo; // 股票代號
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public String m_caName; // 股票名稱
public Int32 m_nOpen; // 開盤價
public Int32 m_nHigh; // 最高價
public Int32 m_nLow; // 最低價
public Int32 m_nClose; // 成交價
public Int32 m_nTickQty; // 單量
public Int32 m_nRef; // 昨收、參考價
public Int32 m_nBid; // 買價
public Int32 m_nBc; // 買量
public Int32 m_nAsk; // 賣價
public Int32 m_nAc; // 賣量
public Int32 m_nTBc; // 買盤量
public Int32 m_nTAc; // 賣盤量
public Int32 m_nFutureOI; // 期貨未平倉 OI
public Int32 m_nTQty; // 總量
public Int32 m_nYQty; // 昨量
public Int32 m_nUp; // 漲停價
public Int32 m_nDown; // 跌停價
}

// [struct] TTick
[StructLayout(LayoutKind.Sequential)]
public struct TTick
{
public Int32 m_nPtr; // 資料所在的位置(Key)
public Int32 m_nTime; // 時間
public Int32 m_nBid; // 買價
public Int32 m_nAsk; // 賣價
public Int32 m_nClose; // 成交價
public Int32 m_nQty; // 成交量
}


/*
* [In,Out] ref Variable
*/

// PageNo
static short PageNo = -1;

// TStock
public static TStock Stock = new TStock();

// Tick
public static TTick Tick = new TTick();




private void Form1_Load(object sender, EventArgs e)
{
    // 0.初始使用者相關資訊
    SKQuoteLib_Initialize("身分證號", "密碼");

    // 1.0.向報價函式庫註冊接收連線狀態的 Call back 函式位址
    SKQuoteLib_AttachConnectionCallBack(Delegate_AttachConnection);
  
    // 1.1.當有索取的個股報價異動時,將透過此註冊的函式通知應用程式處理
    SKQuoteLib_AttachQuoteCallBack(Delegate_AttachQuote);
  
    // 1.2.當有索取的個股成交明細有所異動,即透過向此註冊的Call back 函式進行處理
    SKQuoteLib_AttachTicksCallBack(Delegate_AttachTicks);
  
    // 1.3.當有索取的個股五檔價格有所異動,即透過向此註冊的Call back 函式進行處理
    SKQuoteLib_AttachBest5CallBack(Delegate_AttachBest5);

    // 2.建立與報價伺服器的連線
    SKQuoteLib_EnterMonitor();
}




// 1.0
public static void CBFunc_AttachConnection(int nKind, int nCode)
{
    Console.WriteLine("[Connection] Kind: {0}, Code: {1}", nKind, nCode);
}

// 1.1
public static void CBFunc_AttachQuote(short sMarketNo, short sStockidx)
{
    Console.WriteLine("[Quoto] MarketNo: {0}, Stockidx: {1}", sMarketNo, sStockidx);
    // 在這裡做 SKQuoteLib_GetStockByIndex
}

// 1.2
public static void CBFunc_AttachTicks(short sMarketNo, short sStockidx, int nPtr)
{
    Console.WriteLine("[Ticks] MarketNo: {0}, Stockidx: {1}", sMarketNo, sStockidx);
    // 5. SKQuoteLib_GetTick
    SKQuoteLib_GetTick(sMarketNo, sStockidx, nPtr, ref Tick);
}

// 1.3
public static void CBFunc_AttachBest5(short sMarketNo, short sStockidx)
{
    Console.WriteLine("[Best5] MarketNo: {0}, Stockidx: {1}", sMarketNo, sStockidx);
    // 在這裡做 SKQuoteLib_GetBest5
}



private void button1_Click(object sender, EventArgs e)
{
    // 3. SKQuoteLib_GetStockByNo
    SKQuoteLib_GetStockByNo(textBox1.Text, ref Stock);
    // 4. SKQuoteLib_RequestTicks
    SKQuoteLib_RequestTicks(ref PageNo, textBox1.Text);
}



private void button2_Click(object sender, EventArgs e)
{
    // END. SKQuoteLib_LeaveMonitor
    SKQuoteLib_LeaveMonitor();
}

}

5 則留言:

Unknown 提到...

Percy大您好

請問你有研究出為什麼在Conso模式不能進入讓callback函式嗎??

Unknown 提到...

您好
我用visual basic 2008,報價(數字)ok,但是股票名稱卻是空字串(無法秀出中文),可是excel範例卻可正確秀出中文股票名稱。
請問您的執行結果可否秀出中文股票名稱呢?
謝謝

steven

Nickcat Wang 提到...

percy 大~小弟轉貼您的程式碼在這裡
http://www.programtrading.tw/viewtopic.php?f=10&t=7896
如果您覺得不妥,請告訴我
另外,想請教,我直接用亂改您的程式
增加了:
' 3.2根據MarketNo+Index取得報價資訊
_
Private Shared Function SKQuoteLib_GetStockByIndex(ByRef sMarketNo As Int16, ByRef sIndex As Int16, ByRef pStock As TStock) As Integer
End Function
然後在這裡去套用
Public Shared Sub CBFunc_AttachQuote(ByVal sMarketNo As Short, ByVal sStockidx As Short)
Dim Status As Integer
[color=#FF0000]Status = SKQuoteLib_GetStockByIndex(sMarketNo, sStockidx, _Stock)[/color]
End Sub
但是...結果可想而知,每次都是收到sk_error -1
不知GetStockByIndex要如何使用才能順利運作?
感激~

wdshieh 提到...

您好
我最近也開始研究群益的API
看到這個網頁真是如獲至寶
不過
當我仿照您的例子
做完
SKQuoteLib_Initialize
SKQuoteLib_AttachConnectionCallBack
SKQuoteLib_AttachQuoteCallBack
SKQuoteLib_AttachTicksCallBack
SKQuoteLib_AttachBest5CallBack
SKQuoteLib_EnterMonitor
之後
下一步要用SKQuoteLib_RequestStocks訂閱報價時
怎麼做都不對,老是收到傳回值101(SK_SUBJECT_CONNECTION_DISCONNECT)
我看它的Excel範例,卻是沒問題的
在文件中,SKQuoteLib_RequestStocks的第一個參數是註明為[in,out] short* psPageNo
因此我在c#是用ref short PageNo來做,卻不成功
而且我試著把ref拿掉也一樣不行
奇怪的是我看它的Excel VBA範例裏直接下
SKQuoteLib_RequestStocks(-1, ComIds)卻是可以成功的
但我在c#裏直接下-1也是一樣不行

不知您可否給我些意見?
謝謝了!

ruru 提到...

Percy,
請問群益API的Stock.dat 是再程式呢哪一個階段被執行呢?
因執行程式後,一值發生Stock.dat size=0感到非常的困惑

ruru

張貼留言