【问题标题】:How to form 5 minutes open high low close values from a continuous coming data c#? [closed]如何从连续的数据c#中形成5分钟的开高低收盘值? [关闭]
【发布时间】:2020-10-16 07:14:08
【问题描述】:

我有一个 websocket api,它每秒不断地给我数据。我的目标是根据这些数据形成一个 5 分钟的开盘收盘价低点。

这是 Python 代码,它们在 Python 中也是如此:https://gist.github.com/oldmonkABA/f73f5d67bcf85316ac0470919bf54e17

我尝试如下OnTick 方法每 1 秒调用一次,每秒数据如下:

{"InstrumentToken":260105,"LastPrice":23616.6,"Timestamp":"2020-10-16T16:35:01"}

所以我会在每秒之后得到具有不同 LastPrice 和 Timestamp 的相同 json,例如:

{"InstrumentToken":260105,"LastPrice":23620,"Timestamp":"2020-10-16T14:38:02"}

{"InstrumentToken":260105,"LastPrice":23622,"Timestamp":"2020-10-16T14:38:03"}

以此类推,直到:

{"InstrumentToken":260105,"LastPrice":23644,"Timestamp":"2020-10-16T14:39:59"}

现在在下面的对象 latestTickData 我正在收集所有这些数据,预期的输出是:

open = 23616.6,因为它是基于“Timestamp”:“2020-10-16T14:35:01”的起始价格。

close = 23644,基于其最近 5 分钟的价格 "Timestamp":"2020-10-16T14:39:59"。

high = 我可以使用 MAX(所有 5 分钟数据)。

低 = 我可以使用 MIN(所有 5 分钟数据)

C#代码:

private static void OnTick(Tick TickData)
{
    Console.WriteLine("Tick " + Utils.JsonSerialize(TickData));

    var latestTickData = new MyObject()
    {
        InstrumentID = TickData.InstrumentToken,
        Close = TickData.LastPrice,
        High = TickData.LastPrice,
        Low = TickData.LastPrice,
        Open = TickData.LastPrice,
        TimeStamp = TickData.Timestamp.HasValue ? TickData.Timestamp.Value : DateTime.Now
    };

现在我将每秒收集一个新数据到latestTickData

我想根据这个数据形成一个 5 分钟的开盘收盘高低。

我正在考虑对时间戳和 min max 函数进行类似 group by 以查找低位和高位,但代码不起作用。

我尝试使用此代码,但此代码超出 ontick 计算持续数据的方法:

var resultSet = MydataList.GroupBy(i => i.GetStartOfPeriodByMins(5))
           .Select(gr =>
          new
          {
              StartOfPeriod = gr.Key,
              Low = gr.Min(item => item.Low),
              High = gr.Max(item => item.High),
              Open = gr.OrderBy(item => item.TimeStamp).First().Open,
              Close = gr.OrderBy(item => item.TimeStamp).Last().Close
          });


public DateTime GetStartOfPeriodByMins(int numMinutes)
    {
        int oldMinutes = TimeStamp.Minute;
        int newMinutes = (oldMinutes / numMinutes) * numMinutes;

        DateTime startOfPeriod = new DateTime(TimeStamp.Year, TimeStamp.Month, TimeStamp.Day, TimeStamp.Hour, newMinutes, 0);

        return startOfPeriod;
    }

【问题讨论】:

  • “我要识别开收高低数据”那是什么?
  • 让我重新表述我的问题。你能定义什么是开放数据吗?高数据?低数据?关闭数据?
  • 您的问题是什么?请附上minimal reproducible example,说明该代码的作用、您希望它做什么以及具体您需要什么帮助。 LINQ 对数据项的枚举(序列)进行操作;您的帖子中没有任何内容显示任何数据结构,这些数据结构会累积您似乎想要处理的数据,更不用说任何显示您尝试处理它的内容。
  • 听起来像是某种“时间序列”——你在天蓝色吗?
  • 我认为您需要查看Rx.Net。它具有可能对您有所帮助的操作。 P.S.:不要搜索 RX.NET 本身!!!!我已经链接到github了。

标签: c# .net linq


【解决方案1】:

有很多方法可以做到这一点,这取决于您需要读取数据的频率,以及是否值得在每个滴答声中更新缓存,或者您需要一个计时器来保持刷新,或者您只是想计算它在飞行中。

无论如何,我选择了一个队列 来管理系列,我还选择了在每个滴答时更新缓存(正确或错误)。您可以轻松地使用列表,并实时过滤/查询,我将把所有这些细节留给您。

给定

public class Tick
{
   public int Instrument { get; set; }
   public DateTime TimeStamp { get; set; }
   public decimal LatestPrice { get; set; }
}

public class Data
{
   private readonly Queue<Tick> _queue = new Queue<Tick>();
   public decimal High { get; private set; }
   public decimal Low { get; private set; }
   public decimal Open { get; private set; }
   public decimal Close { get; private set; }

   public void Add(Tick tick)
   {
      _queue.Enqueue(tick);
      Update();
   }

   public void Update()
   {
      var age = DateTime.Now.AddMinutes(-5);
      while (_queue.Any() && _queue.Peek().TimeStamp < age)
         _queue.Dequeue();

      High = _queue.Max(x => x.LatestPrice);
      Low = _queue.Min(x => x.LatestPrice);
      Open = _queue.LastOrDefault()?.LatestPrice ?? 0;
      Close = _queue.FirstOrDefault()?.LatestPrice ?? 0;

   }
}

存放它的字典

private Dictionary<int,Data> _instruments = new Dictionary<int, Data>();

用法

// add data
if(!_instruments.TryGetValue(tick.Instrument, out var data))
   _instruments.Add(tick.Instrument, data = new Data());
data.Add(tick);

...

var Ohcl = _instruments[TickData.Instrument];

// example reading the data
Console.WriteLine(Ohcl.High);

如果你想即时计算

public class Data
{
   private readonly Queue<Tick> _queue = new Queue<Tick>();
   public decimal High => _queue.Max(x => x.LatestPrice);
   public decimal Low => _queue.Min(x => x.LatestPrice);
   public decimal Open => _queue.LastOrDefault()?.LatestPrice ?? 0;
   public decimal Close => _queue.FirstOrDefault()?.LatestPrice ?? 0;

   public void Add(Tick tick)
   {
      _queue.Enqueue(tick);
      Update();
   }

   public void Update()
   {
      var age = DateTime.Now.AddMinutes(-5);
      while (_queue.Any() && _queue.Peek().TimeStamp < age)
         _queue.Dequeue();
   }
}

注意:这并不是一个完整的解决方案,它缺乏健全性检查和一大堆可能与您相关的细节。性能和效率也由您自行决定

【讨论】:

  • @Neo 有点难以继续前进,因为这只是一个例子,它真的取决于你在做什么和想要做什么以及你是如何做的。也许只是玩弄它,看看你的进展如何,如果你有更深层次的问题,可能值得再问一个问题......但我建议看看我已经展示的解决方案并尝试理解它,然后玩
  • 不是批评,只是指出 OP:这是 not 线程安全的!这些方法不是原子的,因此您可能需要在应用程序中考虑这一点。
  • @Fildor 是的,非常好。
  • @Neo 数据库使这成为一个完全不同的问题。您只需查询最后 5 分钟。请注意,这是最理智的方法。
  • “我会将每个刻度数据添加到 cosmos db 中,但不确定如何仅获取最近 5 分钟的数据?” - 这将是另一个问题,应该单独提出。 :)
【解决方案2】:

编辑: 正如@Cid 所提到的,第一种方法假定数据是定期出现的,但很可能永远不会出现这种情况,并且很有可能出错。最好的方法是尝试第二种方法,其中有两个变量并进行比较时间戳。


这个问题有多种解决方法。你提到你每 1 秒获取一次数据,那么例如你可以有一个变量来计算你收集了多少条数据:

//before first element has come
int numberOfData=0;

并且在每个厚之后,您只需增加 numberOfData。当 numberOfData 为 300(5*60s) 时,假设您每隔一秒获取一次数据,那么五分钟过去了。


另一种方法是,您有两个变量 firstData 和 lastData,它们最初设置为 null。然后分配 firstData 的第一个 TickData,而不仅仅是比较 firstData 和即将到来的新 TickData 对象之间的时间戳。当差异是5 分钟后,您可以将该对象分配给 lastData。

【讨论】:

  • 只要您每1.0000 秒完美地获取数据,这将起作用。想象一下,获取它们需要1.1 秒,您将拥有 10% 的不应该存在的数据
  • 是的,您有意见,感谢您的评论。
  • 有时我们可能无法在几秒钟内从服务器获取数据,我的意思是留出 1-2 秒我们也可以获得
猜你喜欢
  • 1970-01-01
  • 2018-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-31
相关资源
最近更新 更多