4

私の取引アプリケーションには、株価の「ライブ ティック」があります。SMAを維持する必要があります。各ろうそくの持続時間が 10 秒である 20 本のろうそくの SMA が必要であると仮定しましょう。この意味は

10秒ごとに「チェックポイント」があります。

  1. 現在のろうそくを「クローズ」し、最後の 10 秒間の平均価格を保存します。平均は (最大 - 最小) / 2
  2. 私は新しいろうそくを「開始」し、最終価格を保存します。
  3. 「時代遅れの」ろうそくを片付けます。

ティックごと:

  1. 現在の「フォーミング」ろうそくの「最終」価格を更新し、SMA を再計算します。

したがって、どのティックでも、SMA を「再計算」する必要があります。ほとんどの場合、最後のろうそくの価格のみが変更されます (最後の価格を使用しているため)。10 秒に 1 回、もう少し余分な作業が必要です。古いろうそくの平均を「忘れ」、「作成したばかり」のろうそくの平均を「保存」する必要があります。

これを最小のレイテンシで実装する方法を提案できますか? 低遅延が主な要件です。

4

3 に答える 3

0

したがって、新しいアイテムを効率的に追加し、最も古いアイテムを削除できる (現在の合計から削除するため) ほぼ固定サイズのキューが必要です。なぜstd::queueですか?

これはさまざまなコンテナの上に置くことができますが、実際に要素が 20 個しかない場合はvector、うまく機能すると思います。(アイテムを削除するには、他のすべてのアイテムを 1 つ下に移動する必要がありますが、メモリの連続したブロックを移動するのは高速です。) ただし、パフォーマンスを両端キューまたはリストと比較することをお勧めします。

(答えは、各「ろうそく」に何を保存するかによって異なります-単一のfloat / double / int、またはより複雑な構造ですか?)

于 2014-04-28T21:21:13.127 に答える
0

私の実装。.h:

#pragma once

#include <deque>

class MovingAverage
{
public:
    MovingAverage(int length);
    ~MovingAverage(void);
    void Add(double val);
    void Modify(double value);
    double Value;
    std::deque<double> _candlesExceptNewest;
private:
    MovingAverage(MovingAverage& rhs):
        _length(rhs._length)
    {
        printf("MovingAverage copy-constructor mustn't be executed, exiting.");
        exit(0);
    }

    const int _length;

    int addCounter;
    static const int RECALCULATE_VALUE_MASK;

    double _sumExceptNewest;

    double NewestCandleMedian() {
        return (_newestCandleMin + _newestCandleMax) / 2;
    }
    void RecalculateValue();
    double _newestCandleMin;
    double _newestCandleMax;
};

.cpp:

#include "MovingAverage.h"
#include "CommonsNative.h"

const int MovingAverage::RECALCULATE_VALUE_MASK = 1024 - 1;

MovingAverage::MovingAverage(int length):
    Value(quiet_NaN),
    _length(length),
    addCounter(0)
{
    if (length < 20) {
        std::cout << "Warning, MA is very short, less than 20! length = " 
            << length << std::endl;
    }
}

MovingAverage::~MovingAverage(void)
{
}

void MovingAverage::Add(double val)
{
    ++addCounter;
    if (addCounter & RECALCULATE_VALUE_MASK) {
        _sumExceptNewest = 0;
        for (double val : _candlesExceptNewest)
        {
            _sumExceptNewest += val;
        }
    }

    auto curQueueSize = _candlesExceptNewest.size();
    if (curQueueSize == 0) {
        _newestCandleMax = _newestCandleMin = val;
    }
    _sumExceptNewest += NewestCandleMedian();
    _candlesExceptNewest.push_back(NewestCandleMedian());
    if (curQueueSize == _length) {
        _sumExceptNewest -= _candlesExceptNewest.front();
        _candlesExceptNewest.pop_front();
    }
    _newestCandleMax = _newestCandleMin = val;
    RecalculateValue();
}

void MovingAverage::RecalculateValue()
{
    Value = (_sumExceptNewest + NewestCandleMedian())/(_candlesExceptNewest.size() + 1);
}

void MovingAverage::Modify(double val)
{
    if (_candlesExceptNewest.size() == 0) {
        Add(val);
    } else {
        if (val > _newestCandleMax) {
            _newestCandleMax = val;
        } 
        if (val < _newestCandleMin) {
            _newestCandleMin = val;
        }
    }
}
于 2014-07-13T06:07:29.513 に答える