首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >第二次调用TWS API中的reqContractDetails没有发送任何通知并挂起

第二次调用TWS API中的reqContractDetails没有发送任何通知并挂起
EN

Stack Overflow用户
提问于 2018-06-05 16:47:56
回答 1查看 617关注 0票数 1

试图创建一种市场扫描仪。下面的代码应该返回期权合同链。对TWS API的调用是一个异步方法,仅当我从TWS获得ContractEnd或错误响应时才返回一些数据。在第一次调用reqContractDetails()时,它按预期工作,我获得了合同列表,接收到消息"ContractEnd",然后退出该方法。

障碍物

出于某种原因,在第二次调用reqContractDetails()时,我没有收到来自TWS的任何通知。我必须停止并重新启动我的应用程序,启动到服务器的新连接才能使其再次工作。

更新

在重构我的代码后,我在第二次调用时得到一个错误,说“无法读取超出流的末尾”。调用堆栈看起来是这样的。

代码语言:javascript
运行
复制
IBLibrary.dll!IBLibrary.OptionService.GetOptionsChain.AnonymousMethod__3(IBLibrary.Messages.ErrorMessage data) Line 64
IBLibrary.dll!IBLibrary.Classes.Client.error(string str) Line 42
CSharpAPI.dll!IBApi.EReader.putMessageToQueue() Line 94
CSharpAPI.dll!IBApi.EReader.Start.AnonymousMethod__9_0() Line 48

在C#中我的包装器实现

代码语言:javascript
运行
复制
public class BaseService : IDisposable
{
  protected Client Sender { get; set; }
  protected EReader Receiver { get; set; }

  public BaseService()
  {
    Sender = new Client();
    Sender.Socket.eConnect("127.0.0.1", 7496, 0);
    Receiver = new EReader(Sender.Socket, Sender.Signal);
    Receiver.Start();

    var process = new Thread(() =>
    {
      while (Sender.Socket.IsConnected())
      {
        Sender.Signal.waitForSignal();
        Receiver.processMsgs();
      }
    })
    {
      IsBackground = true
    };

    process.Start();
  }

  public void Dispose()
  {
    Sender.Socket.eDisconnect();
  }
}

public class OptionService : BaseService
{
  public Task<List<OptionModel>> GetOptionsChain(OptionModel query)
  {
    if (query == null)
    {
      query = new OptionModel();
    }

    var process = Task.Run(() =>
    {
      var done = false;
      var id = new Random(DateTime.Now.Millisecond).Next();

      var contract = new Contract
      {
        Symbol = query.Symbol,
        SecType = "OPT",
        Exchange = "SMART",
        Currency = "USD",
        LastTradeDateOrContractMonth = query.Expiration
      };

      var contracts = new List<OptionModel>();

      Action<ErrorMessage> errorMessage = null;
      Action<ContractDetailsMessage> contractMessage = null;
      Action<ContractDetailsEndMessage> contractMessageEnd = null;

      contractMessage = (ContractDetailsMessage data) =>
      {
        contracts.Add(new OptionModel
        {
          Symbol = data.ContractDetails.Contract.Symbol,
          Right = data.ContractDetails.Contract.Right,
          Strike = data.ContractDetails.Contract.Strike,
          Expiration = data.ContractDetails.RealExpirationDate
        });
      };

      // I receive this message at first, but not the second time

      contractMessageEnd = (ContractDetailsEndMessage data) =>
      {
        done = true;
      };

      errorMessage = (ErrorMessage data) =>
      {
        var notifications = new List<int>
        {
          (int) ErrorCode.MarketDataFarmConnectionIsOK,
          (int) ErrorCode.HmdsDataFarmConnectionIsOK
        };

        if (notifications.Contains(data.ErrorCode) == false)
        {
          done = true;
        }
      };

      Sender.ErrorEvent += errorMessage;
      Sender.ContractDetailsEvent += contractMessage;
      Sender.ContractDetailsEndEvent += contractMessageEnd;
      Sender.Socket.reqContractDetails(id, contract);

      // Execute method until we get all contracts
      // The econd call to reqContractDetails doesn't return 
      // any notification, so obviously this line hangs forever

      while (done == false);

      Sender.ErrorEvent -= errorMessage;
      Sender.ContractDetailsEvent -= contractMessage;
      Sender.ContractDetailsEndEvent -= contractMessageEnd;

      return contracts;
    });

    return process;
  }
}
EN

Stack Overflow用户

回答已采纳

发布于 2018-06-07 08:13:28

到目前为止,没有人知道答案,即使是IB本身,我看到的唯一解决方案是,将我的API控制器转换为同步控制器,并在每次请求后关闭到IB服务器的套接字连接。

旧版本。

代码语言:javascript
运行
复制
public class ServiceOptionsController : BaseServiceController
{
  OptionService Service = new OptionService();

  [AcceptVerbs("POST")]
  public async Task<List<OptionModel>> Options([FromBody] dynamic data)
  {
    var selectors = data.ToObject<QueryModel>();

    var optionModel = new OptionModel
    {
      Symbol = "MSFT",
      Expiration = "201806"
    };

    var processes = new List<Task<List<OptionModel>>>
    {
      Service.GetOptionsChain(optionModel)
    };

    return (await Task.WhenAll(processes)).SelectMany(o => o).ToList();
  }
}

工作版本。

代码语言:javascript
运行
复制
public class ServiceOptionsController : BaseServiceController
{
  [AcceptVerbs("POST")]
  public List<OptionModel> Options([FromBody] dynamic data)
  {
    var selectors = data.ToObject<QueryModel>();

    var optionModel = new OptionModel
    {
      Symbol = "MSFT",
      Expiration = "201806"
    };

    var optionService = new OptionService();

    var processes = new List<Task<List<OptionModel>>>
    {
      optionService.GetOptionsChain(optionModel)
    };

    var items = Task.WhenAll(processes).Result.SelectMany(o => o).ToList();

    optionService.Dispose(); // Ridiculous fix for ridiculous API

    return items;
  }
}
票数 1
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50695910

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档