Дмитрий А можете релизацию этого интерфейса в объекте trader показать? Пусть даже сильно обрезанную. Чтобы все методы и событие интерфейса были описаны.
Честно говоря, из этого кода по-прежнему не ясно, что делать.
Я правильно понял, что мой класс будет забирать данные из массива, и класть их в MySource.Trades именно в методе AddTrades? И какая специфика есть в SafeInvoke? Что-то с многопоточностью связанное?
Код
namespace Ecng.Trading.Algo.Candles
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Ecng.Collections;
using Ecng.Common;
using Ecng.Trading.BusinessEntities;
/// <summary>
/// Базовый источник тиковых сделок для <see cref="CandleManager"/>, получаемых через событие <see cref="ITrader.NewTrades"/>.
/// </summary>
public abstract class TraderCandleSource : Disposable, ICandleSource
{
private readonly int _maxTradeCount;
private readonly int _maxCandleCount;
private readonly SynchronizedList<Trade> _trades;
private readonly SynchronizedDictionary<Candle, SynchronizedList<Trade>> _candleTrades;
/// <summary>
/// Инициализировать <see cref="TraderCandleSource"/>.
/// </summary>
/// <param name="trader">Торговый шлюз, у которого используется событие <see cref="ITrader.NewTrades"/>.</param>
/// <param name="maxTradeCount">Максимальное количество сделок, которые нужно хранить.</param>
/// <param name="maxCandleCount">Максимальное количество свечек, которые нужно хранить.</param>
protected TraderCandleSource(ITrader trader, int maxTradeCount, int maxCandleCount)
{
if (trader == null)
throw new ArgumentNullException("trader");
this.Trader = trader;
this.Trader.NewTrades += OnNewTrades;
_maxTradeCount = maxTradeCount;
_maxCandleCount = maxCandleCount;
_trades = new SynchronizedList<Trade>(100000);
_candleTrades = new SynchronizedDictionary<Candle, SynchronizedList<Trade>>(1000);
}
/// <summary>
/// Шлюз к торговой системе.
/// </summary>
public ITrader Trader { get; private set; }
/// <summary>
/// Событие появления всех новых сделок.
/// </summary>
public event Action<IEnumerable<Trade>> NewTrades;
/// <summary>
/// Все накопленные сделки.
/// </summary>
public virtual IEnumerable<Trade> Trades
{
get { return _trades.SyncGet(c => c.ToArray()); }
}
/// <summary>
/// Добавить сделку для свечки.
/// </summary>
/// <param name="candle">Свечка, для которой нужно добавить сделку.</param>
/// <param name="trade">Новая сделка.</param>
public void AddTrade(Candle candle, Trade trade)
{
_candleTrades.SafeAdd(candle).Add(trade);
if (_candleTrades.Count > _maxCandleCount * 1.5)
{
_candleTrades.SyncDo(c =>
{
var elapsed = c.Skip(_maxCandleCount / 2).ToArray();
c.Clear();
c.AddRange(elapsed);
});
}
}
/// <summary>
/// Получить все сделки по свечке.
/// </summary>
/// <param name="candle">Свечка, по которой нужно найти сделки.</param>
/// <returns>Найденные сделки.</returns>
public IEnumerable<Trade> GetTrades(Candle candle)
{
var trades = _candleTrades.TryGetValue(candle);
return trades != null ? trades.SyncGet(c => c.ToArray()) : new Trade[0];
}
/// <summary>
/// Обработчик события <see cref="ITrader.NewTrades"/>.
/// </summary>
/// <param name="trades">Новые сделки.</param>
protected virtual void OnNewTrades(IEnumerable<Trade> trades)
{
_trades.AddRange(trades);
if (_trades.Count > _maxTradeCount * 1.5)
{
_trades.SyncDo(c =>
{
var elapsed = c.Skip(_maxTradeCount / 2).ToArray();
c.Clear();
c.AddRange(elapsed);
});
}
}
/// <summary>
/// Вызвать событие <see cref="NewTrades"/>.
/// </summary>
/// <param name="trades">Новые сделки.</param>
protected void RaiseNewTrades(IEnumerable<Trade> trades)
{
this.NewTrades.SafeInvoke(trades);
}
/// <summary>
/// Освободить занятые ресурсы.
/// </summary>
protected override void DisposeManaged()
{
this.Trader.NewTrades -= OnNewTrades;
base.DisposeManaged();
}
}
/// <summary>
/// Источник тиковых сделок для <see cref="CandleManager"/>, получаемых через событие <see cref="ITrader.NewTrades"/>,
/// и отправляемый в <see cref="CandleManager"/> с определенным интервалом.
/// </summary>
public class ParallelTraderCandleSource : TraderCandleSource
{
private readonly SynchronizedList<Trade> _newTrades = new SynchronizedList<Trade>();
private bool _isInProcess;
private readonly Timer _timer;
/// <summary>
/// Создать <see cref="ParallelTraderCandleSource"/>.
/// </summary>
/// <param name="trader">Торговый шлюз, у которого используется событие <see cref="ITrader.NewTrades"/>.</param>
public ParallelTraderCandleSource(ITrader trader)
: this(trader, TimeSpan.FromMilliseconds(300))
{
}
/// <summary>
/// Создать <see cref="ParallelTraderCandleSource"/>.
/// </summary>
/// <param name="trader">Торговый шлюз, у которого используется событие <see cref="ITrader.NewTrades"/>.</param>
/// <param name="interval">Интервал отправки новых сделок.</param>
public ParallelTraderCandleSource(ITrader trader, TimeSpan interval)
: base(trader, int.MaxValue, int.MaxValue)
{
if (trader == null)
throw new ArgumentNullException("trader");
_timer = interval.CreateTimer(OnProcessTrades);
}
/// <summary>
/// Обработчик события <see cref="ITrader.NewTrades"/>.
/// </summary>
/// <param name="trades">Новые сделки.</param>
protected override void OnNewTrades(IEnumerable<Trade> trades)
{
base.OnNewTrades(trades);
_newTrades.AddRange(trades);
}
private void OnProcessTrades()
{
if (_isInProcess)
return;
_isInProcess = true;
try
{
var newTrades = _newTrades.SyncGet(c =>
{
var retVal = c.ToArray();
c.Clear();
return retVal;
});
if (newTrades.Length > 0)
base.RaiseNewTrades(newTrades);
}
finally
{
_isInProcess = false;
}
}
/// <summary>
/// Освободить занятые ресурсы.
/// </summary>
protected override void DisposeManaged()
{
_timer.Dispose();
base.DisposeManaged();
}
}
/// <summary>
/// Источник тиковых сделок для <see cref="CandleManager"/>, получаемых через событие <see cref="ITrader.NewTrades"/>,
/// и хранящий последние полученные сделки за определенный период.
/// </summary>
public class SyncTraderCandleSource : TraderCandleSource
{
/// <summary>
/// Создать <see cref="SyncTraderCandleSource"/>.
/// </summary>
/// <param name="trader">Торговый шлюз, у которого используется событие <see cref="ITrader.NewTrades"/>.</param>
public SyncTraderCandleSource(ITrader trader)
: this(trader, 100000, 1000)
{
}
/// <summary>
/// Создать <see cref="SyncTraderCandleSource"/>.
/// </summary>
/// <param name="trader">Торговый шлюз, у которого используется событие <see cref="ITrader.NewTrades"/>.</param>
/// <param name="maxTradeCount">Максимальное количество сделок, которые нужно хранить.</param>
/// <param name="maxCandleCount">Максимальное количество свечек, которые нужно хранить.</param>
public SyncTraderCandleSource(ITrader trader, int maxTradeCount, int maxCandleCount)
: base(trader, maxTradeCount, maxCandleCount)
{
}
/// <summary>
/// Обработчик события <see cref="ITrader.NewTrades"/>.
/// </summary>
/// <param name="trades">Новые сделки.</param>
protected override void OnNewTrades(IEnumerable<Trade> trades)
{
base.OnNewTrades(trades);
base.RaiseNewTrades(trades);
}
}
}