乐趣区

关于后端:量化交易平台之行情数据获取方式

通过凋谢的形式提供寰球股票(A 股、港股、美股)、期货(国内期货、国际期货)等历史数据查问及实盘实时行情订阅

平台特色:
寰球大多数行情一次购买即可享受全副数据行情订阅。
历史数据能够提供下载服务方便使用
云端自定义指数合成能力
自定义种类的反对(如不同种类的价差 K 线等)
实时行情局部时效性强
行情数据接口,分享代码如下:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static RndInvest.DataPlatform.Ctp.ctp_quote;

namespace RndInvest.DataPlatform.Ctp
{

public abstract class CTPQuote : Quote
{
    ctp_quote _q = null;
    private readonly List<Delegate> _listDele = new List<Delegate>();
    public Thread _doHeartBeatThread;


    /// <summary>
    /// 
    /// </summary>
    public CTPQuote()
    {_q = new ctp_quote();
        SetCallBack();
        _doHeartBeatThread = new Thread(new ThreadStart(HeartBeat));
        _doHeartBeatThread.IsBackground = true;
        _doHeartBeatThread.Start();}

    /// <summary>
    /// 前置地址端口
    /// </summary>
    public override string FrontAddr {get; set;}

    /// <summary>
    /// 帐号 guweng22346
    /// </summary>
    public override string Investor {get; set;}

    /// <summary>
    /// 明码
    /// </summary>
    public override string Password {get; set;}

    /// <summary>
    /// 经纪商代码
    /// </summary>
    public override string Broker {get; set;}

    Delegate AddDele(Delegate d) {_listDele.Add(d); return d; }

    void SetCallBack()
    {_q.SetOnFrontConnected((DeleOnFrontConnected)AddDele(new DeleOnFrontConnected(CTPOnFrontConnected)));
        _q.SetOnRspUserLogin((DeleOnRspUserLogin)AddDele(new DeleOnRspUserLogin(CTPOnRspUserLogin)));
        _q.SetOnFrontDisconnected((DeleOnFrontDisconnected)AddDele(new DeleOnFrontDisconnected(CTPOnFrontDisconnected)));
        _q.SetOnRspSubMarketData((DeleOnRspSubMarketData)AddDele(new DeleOnRspSubMarketData(CTPOnRspSubMarketData)));
        _q.SetOnRtnDepthMarketData((DeleOnRtnDepthMarketData)AddDele(new DeleOnRtnDepthMarketData(CTPOnRtnDepthMarketData)));
        _q.SetOnRspError((DeleOnRspError)AddDele(new DeleOnRspError(CTPOnRspError)));
    }

    private void CTPOnRtnDepthMarketData(ref CThostFtdcDepthMarketDataField pDepthMarketData)
    {
        CThostFtdcDepthMarketDataField f = pDepthMarketData;

        if (string.IsNullOrEmpty(f.InstrumentID) || string.IsNullOrEmpty(f.UpdateTime) || double.IsInfinity(f.UpperLimitPrice))// 过滤无穷大 / 小
        {return;}
        // 修改 last=double.max
        if (Math.Abs(f.LastPrice - double.MaxValue) < double.Epsilon)
        {if (Math.Abs(f.AskPrice1 - double.MaxValue) > double.Epsilon)
            {f.LastPrice = f.AskPrice1;}
            else if (Math.Abs(f.BidPrice1 - double.MaxValue) > double.Epsilon)
            {f.LastPrice = f.BidPrice1;}
            else
                return;
        }

        // 去掉 tradingday 字段
        //if (string.IsNullOrEmpty(f.TradingDay))
        //{
        //    f.TradingDay = this.TradingDay; // 日期: 实盘中某些交易所, 此字段为空
        //}
        //if (string.IsNullOrEmpty(f.ActionDay)) // 此字段可能为空
        //{
        //    f.ActionDay = this.TradingDay;
        //}
        //f.ExchangeID = instrument.ExchangeID;
        // 解决, 单边有挂边的状况
        if (f.AskPrice1 > f.UpperLimitPrice) // 未赋值的数据
        {f.AskPrice1 = f.LastPrice;}
        if (f.BidPrice1 > f.UpperLimitPrice)
        {f.BidPrice1 = f.LastPrice;}
        // 修最高 / 最低
        if (Math.Abs(f.HighestPrice - double.MaxValue) < double.Epsilon)
        {f.HighestPrice = f.AskPrice1;}
        if (Math.Abs(f.LowestPrice - double.MaxValue) < double.Epsilon)
        {f.LowestPrice = f.BidPrice1;}

        MarketData tick = DicTick.GetOrAdd(f.InstrumentID, new MarketData
        {InstrumentID = f.InstrumentID,});


        if (f.UpdateMillisec == 0 && f.UpdateTime == tick.UpdateTime && tick.UpdateMillisec < 990)  // 某些交易所 (如郑商所) 雷同秒数的 ms 均为 0
        {f.UpdateMillisec = tick.UpdateMillisec + 10;}

残缺下续

退出移动版