/// <summary> /// Load historical data into bars /// </summary> /// <param name="bars">Bars object</param> /// <param name="insStoreID">InsStote Id</param> /// <param name="date1">First date (without time)</param> /// <param name="date2">Last date (without time)</param> /// <returns>Async task</returns> public Task LoadHistoryAsync(BarRow bars, int insStoreID, DateTime date1, DateTime date2) { if (date2 == DateTime.MaxValue) { date2 = date2.AddDays(-1); } int d1 = StorageLib.ToDbTime(date1.Date); int d2 = StorageLib.ToDbTime(date2.Date.AddDays(1)); return(Task.Run(() => { var loadedBars = _da.DbContext.Table <BarHistory>() .Where(b => b.InsStoreID == insStoreID && b.Time >= d1 && b.Time < d2) .OrderBy(b => b.Time); bars.SuspendEvents(); foreach (var bar in loadedBars) { bars.AddTick(StorageLib.ToDateTime(bar.Time), bar.OpenPrice, 0); bars.AddTick(StorageLib.ToDateTime(bar.Time), bar.HighPrice, 0); bars.AddTick(StorageLib.ToDateTime(bar.Time), bar.LowPrice, 0); bars.AddTick(StorageLib.ToDateTime(bar.Time), bar.ClosePrice, bar.Volume); } bars.CloseLastBar(); bars.ResumeEvents(); })); }
/// <summary> /// Инициализация потоков исторических данных /// </summary> /// <param name="insID">Инструмент</param> public void InitInsStores(int insID) { var isNewTran = _storage.BeginTransaction(); try { foreach (var tf in _tfs) { var insStore = _insStoreDA.GetInsStore(insID, tf); if (insStore == null) { int insStoreID = _insStoreDA.CreateInsStore(insID, tf, true); insStore = _insStoreDA.GetInsStoreByID(insStoreID); } BarRow bars = new BarRow(tf, insStore.InsID); _insStore_barRow.Add(insStore, bars); if (!_insID_barRows.ContainsKey(insID)) { _insID_barRows.Add(insStore.InsID, new List <BarRow>()); } _insID_barRows[insID].Add(bars); } _storage.Commit(isNewTran); } catch (Exception ex) { _storage.Rollback(isNewTran); _logger.AddException("InsStoreBL:CreateInsStore", ex); } }
public async Task <IBarRow> CreateBarRow(int insId, Timeframes tf, int historyDays) { BarRow bars = new BarRow(tf, _tickDisp, insId); DateTime curDate = DateTime.Today; var endHistoryDate = curDate.AddDays(-1); var startHistoryDate = endHistoryDate.AddDays(-historyDays); await _insStoreBL.LoadHistoryAsync(bars, insId, startHistoryDate, endHistoryDate); _barRows.Add(bars); return(bars); }
public void SubscribeValueRow_fulltest() { IAccountDA accDA = new AccountDAMock(); SeriesData sd = new SeriesData(accDA); int accID = 10; // создали серию и подписали на нее поток int sid = sd.OpenSeries("key1"); BarRow bars = new BarRow(Timeframes.Day, 1); sd.SubscribeValueRow(sid, bars.Close, bars.Dates); // в поток добавляем 10 значений DateTime d = new DateTime(2019, 1, 1, 10, 0, 0); for (int i = 0; i < 10; i++) { bars.AddTick(d, 100, 1); d = d.AddDays(1); } bars.CloseLastBar(); sd.SetAccount(accID); sd.SaveData(); // после сохранения sid уже не актуален, надо использовать series[0].SeriesID var series = accDA.GetSeries(accID).ToList(); Assert.Single(series); // серия одна var vals = accDA.GetValues(series[0].SeriesID).ToList(); Assert.True(vals.Count == 10); // в серии 10 значений // теперь отпишемся от потока sd.SubscribeValueRow(series[0].SeriesID, null, null); // в поток добавляем еще 10 значений for (int i = 0; i < 10; i++) { bars.AddTick(d, 200, 1); d = d.AddDays(1); } bars.CloseLastBar(); // снова запишем данные sd.SaveData(); var vals1 = accDA.GetValues(series[0].SeriesID).ToList(); Assert.True(vals1.Count == 10); // в серии по прежнему 10 значений }
/// <summary> /// Загрузка исторических данных в BarRow. /// Наиболее подходящий InsStore определяется автоматически. /// </summary> /// <param name="bars">BarRow</param> /// <param name="insID">Инструмент</param> /// <param name="date1">Нач дата</param> /// <param name="date2">Кон дата</param> /// <param name="insStoreID">Поток данных для загрузки (если null, то поток будет определен автоматически)</param> /// <returns>Асинхронная задача загрузки. Общее число баров после загрузки.</returns> public async Task <int> LoadHistoryAsync(BarRow bars, int insID, DateTime date1, DateTime date2, int?insStoreID = null) { Instrum instrum = _instrumBL.GetInstrumByID(insID); if (instrum == null) { return(0); } if (insStoreID == null) { var insStore = GetLoadHistoryInsStore(insID, bars.Timeframe); if (insStore != null) { insStoreID = insStore.InsStoreID; } } if (insStoreID == null) { return(0); } int k = (int)Math.Pow(10, instrum.Decimals); var list = await _insStoreDA.GetHistoryAsync(insStoreID.Value, date1, date2); return(await Task.Run(() => { bars.SuspendEvents(); foreach (var bar in list) { DateTime time = StorageLib.ToDateTime(bar.Time); decimal openPrice = (decimal)bar.OpenPrice / k; decimal lowPrice = (decimal)(bar.OpenPrice + bar.LowDelta) / k; decimal highPrice = (decimal)(bar.OpenPrice + bar.HighDelta) / k; decimal closePrice = (decimal)(bar.OpenPrice + bar.CloseDelta) / k; bars.AddTick(time, openPrice, 0); bars.AddTick(time, lowPrice, 0); bars.AddTick(time, highPrice, 0); bars.AddTick(time, closePrice, bar.Volume); } bars.CloseLastBar(); bars.ResumeEvents(); return bars.Count; })); }
/// <summary> /// Add prices object to chart /// </summary> /// <param name="bars">Price bars</param> /// <param name="brush">Brush</param> /// <param name="isLeftAxis">Left or right Y-axis</param> public void AddPrices(BarRow bars, ChartBrush brush, bool isLeftAxis = false) { if (bars.Dates != _timeline) { throw new Exception("Timeline incorrect."); } PriceChart vis = new PriceChart(bars, brush); vis.Changed += vis_Changed; if (isLeftAxis) { _leftVisuals.Add(_visualKey++, vis); } else { _rightVisuals.Add(_visualKey++, vis); } }
/// <summary> /// Получить массив баров по другому массиву баров (более мелкому) /// </summary> /// <param name="insID">Инструмент</param> /// <param name="tf">ТФ нового массива</param> /// <param name="minBars">Старый массив</param> /// <param name="cancel">Токен отмены</param> /// <returns>Новый массив баров из старого</returns> public BarRow ConvertBars(int insID, Timeframes tf, IEnumerable <Bar> minBars, CancellationToken cancel) { BarRow barRow = new BarRow(tf, insID); foreach (var minBar in minBars) { if (cancel.IsCancellationRequested) { break; } barRow.AddTick(minBar.Time, minBar.Open, 0); barRow.AddTick(minBar.Time, minBar.High, 0); barRow.AddTick(minBar.Time, minBar.Low, 0); barRow.AddTick(minBar.Time, minBar.Close, minBar.Volume); } barRow.CloseLastBar(); return(barRow); }
public async Task<IBarRow> CreateBarRow(int insID, Timeframes tf, int historyDays) { BarRow bars = new BarRow(tf, _tickSource, insID); var insStore = _insStoreBL.GetLoadHistoryInsStore(insID, tf); // наиболее подходящий insStore if (insStore == null) return null; DateTime? curDate = _tickSource.CurrentTime; if (curDate == null) return null; var endHistoryDate = curDate.Value.AddDays(-1); var startHistoryDate = _insStoreBL.GetStartHistoryDate(insStore.InsStoreID, endHistoryDate, historyDays); if (startHistoryDate != null) { await _insStoreBL.LoadHistoryAsync(bars, insID, startHistoryDate.Value, endHistoryDate, insStore.InsStoreID); } _barRows.Add(bars); return bars; }
public async Task <int> LoadHistoryAsync(BarRow bars, int insID, DateTime date1, DateTime date2, int?insStoreID = null) { if (insStoreID != null) { await _insStoreDA.LoadHistoryAsync(bars, insStoreID.Value, date1, date2); return(bars.Count); } else { var ss = GetLoadHistoryInsStore(insID, bars.Timeframe); if (ss == null) { return(0); } await _insStoreDA.LoadHistoryAsync(bars, ss.InsStoreID, date1, date2); return(bars.Count); } }
private void CreateBarRowSource(Instrum ins, Timeframes tf, string guid) { BarRow bars = new BarRow(tf, ins.InsID); _chartData = new ChartData(bars.Dates, ins.Decimals, _isDynamic); _chartData.AddPrices(bars, new ChartBrush(0, 0, 0)); _guid_source.Add(guid, new PriceSource() { Bars = bars, Instrum = ins }); _srcProv.Initialize(new List <ValueRowSource>() { new ValueRowSource(guid + ":O", "Open", bars.Open, bars), new ValueRowSource(guid + ":H", "High", bars.High, bars), new ValueRowSource(guid + ":L", "Low", bars.Low, bars), new ValueRowSource(guid + ":C", "Close", bars.Close, bars), new ValueRowSource(guid + ":T", "Typical", bars.Typical, bars), new ValueRowSource(guid + ":M", "Median", bars.Median, bars) }); }
public Task Generate(int accountID, Timeline timeline) { return(Task.Run(() => { _cashRow.Clear(); _portfolioRow.Clear(); _equityRow.Clear(); _prices.Clear(); var trades = _accountDA.GetTrades(accountID).OrderBy(r => r.Time).ToList(); var account = _accountDA.GetAccountByID(accountID); var cash = _accountDA.GetCash(accountID); List <EqHold> eqHoldList = new List <EqHold>(); decimal cashSumma = cash.Initial; decimal pfSumma = 0; var bd1 = timeline.GetBarDate(0); var bd2 = timeline.GetBarDate(timeline.Count - 1); if (bd1 == null || bd2 == null) { return; } DateTime date1 = bd1.Value.Start.Date; DateTime date2 = bd2.Value.NextStart.Date; // для таймфреймов day и week загрузим историю на один лишний день int tradeIdx = 0; for (int i = 0; i < timeline.Count; i++) { var barDates = timeline.GetBarDate(i); if (barDates == null) { continue; } while (tradeIdx < trades.Count && trades[tradeIdx].Time < barDates.Value.NextStart) { var trade = trades[tradeIdx]; var instrum = _instrumBL.GetInstrumByID(trade.InsID); // из кеша var tradeSumma = trade.Price * trade.LotCount * instrum.LotSize; var hold = eqHoldList.FirstOrDefault(r => r.InsID == instrum.InsID); if (trade.BuySell == BuySell.Buy) { cashSumma -= tradeSumma; if (hold != null) { hold.LotCount += trade.LotCount; } else { eqHoldList.Add(new EqHold() { InsID = instrum.InsID, LotSize = instrum.LotSize, LotCount = trade.LotCount }); } } else { cashSumma += tradeSumma; if (hold != null) { hold.LotCount -= trade.LotCount; if (hold.LotCount == 0) { eqHoldList.Remove(hold); } } else { eqHoldList.Add(new EqHold() { InsID = instrum.InsID, LotSize = instrum.LotSize, LotCount = -trade.LotCount }); } } tradeIdx++; } // вычисляем сумму портфеля на конец бара pfSumma = 0; foreach (var hold in eqHoldList) { if (!_prices.ContainsKey(hold.InsID)) { BarRow barRow = new BarRow(timeline.Timeframe, hold.InsID); _insStoreBL.LoadHistoryAsync(barRow, hold.InsID, date1, date2).Wait(); _prices.Add(hold.InsID, barRow); } var bars = _prices[hold.InsID]; var bar = bars.Bars.FirstOrDefault(r => r.Time == barDates.Value.Start); if (bar != null) { pfSumma += bar.Close * hold.LotCount * hold.LotSize; } } _cashRow.Add(cashSumma); _portfolioRow.Add(pfSumma); _equityRow.Add(cashSumma + pfSumma); } })); }
public PriceChart(BarRow bars, ChartBrush brush) { this._bars = bars; this._bars.OnChangeBar += bars_OnChangeBar; this._brush = brush; }
/// <summary> /// Вывод исторических данных /// </summary> /// <param name="args">Tf, Ticker, Date1, Date2</param> public void GetBars(List <string> args) { if (args.Count < 4) { _console.WriteError("Неверное число аргументов"); return; } Timeframes tf; if (!Timeframes.TryParse <Timeframes>(args[0], out tf)) { _console.WriteError("Неверный агрумент: Timeframe"); return; } string ticker = args[1]; var instrum = _instrumBL.GetInstrum(ticker); if (instrum == null) { _console.WriteError("Тикер не найден"); return; } DateTime date1, date2; DateTime d; if (DateTime.TryParse(args[2].Trim(), out d)) { date1 = d; } else { _console.WriteError("Неверно указана дата начала"); return; } if (DateTime.TryParse(args[3].Trim(), out d)) { date2 = d; } else { _console.WriteError("Неверно указана дата окончания"); return; } BarRow bars = new BarRow(tf, instrum.InsID); _insStoreBL.LoadHistoryAsync(bars, instrum.InsID, date1, date2).Wait(); _console.WriteLine("Time\t\t\tOpen\tHigh\tLow\tClose\tVolume"); _console.WriteSeparator(); string format = "0." + (new string('0', instrum.Decimals)); foreach (var bar in bars.Bars) { _console.WriteLine(string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}", bar.Time.ToString("dd.MM.yyyy HH:mm:ss"), bar.Open.ToString(format), bar.High.ToString(format), bar.Low.ToString(format), bar.Close.ToString(format), bar.Volume)); } _console.WriteSeparator(); _console.WriteLine("Count: " + bars.Count.ToString()); }
/// <summary> /// Загрузка тиковых данных для всех инструментов /// </summary> /// <returns>Общее кол-во загруженных тиков</returns> public async Task <int> LoadDataAsync() { lock (_ticks) { _ticks.Clear(); } _synTicksCount = _realDays = _synDays = 0; _insID_lastTick.Clear(); foreach (var instrum in _instrums) { if (Timeframe != Timeframes.Tick) { var barRow = new BarRow(Timeframe, instrum.InsID); await _insStoreBL.LoadHistoryAsync(barRow, instrum.InsID, StartDate, EndDate); await Task.Run(() => { foreach (var bar in barRow.Bars) { lock (_ticks) { int v = bar.Volume < int.MaxValue ? (int)bar.Volume : int.MaxValue; _ticks.Add(new Tick(0, bar.Time, instrum.InsID, 0, bar.Open)); _ticks.Add(new Tick(0, bar.Time, instrum.InsID, 0, bar.High)); _ticks.Add(new Tick(0, bar.Time, instrum.InsID, 0, bar.Low)); _ticks.Add(new Tick(0, bar.Time, instrum.InsID, v, bar.Close)); } } }); } else { List <DateTime> freeDays = null; var minInsStore = _insStoreBL.GetInsStore(instrum.InsID, Timeframes.Min); if (minInsStore != null) { freeDays = _insStoreBL.GetInsStoreCalendar(minInsStore.InsStoreID).FreeDays .Where(d => d >= StartDate && d <= EndDate).ToList(); } DateTime date = StartDate; while (date <= EndDate) { var ticks = await _tickHistoryBL.GetTicksAsync(instrum.InsID, date); if (ticks != null && ticks.Any()) { lock (_ticks) { _ticks.AddRange(ticks); } _realDays++; } else // тиковых данных нет, попробуем загрузить минутки и сделать из них тики { if (freeDays != null && !freeDays.Contains(date)) // дата не является выходным днем, значит должны быть минутки { BarRow barRow = new BarRow(Timeframes.Min, instrum.InsID); await _insStoreBL.LoadHistoryAsync(barRow, instrum.InsID, date, date, minInsStore.InsStoreID); if (barRow.Bars.Any()) { foreach (Bar bar in barRow.Bars) { var synTicks = SynTicks(bar, instrum); // синтезируем тики из минутного бара _synTicksCount += synTicks.Count(); _ticks.AddRange(synTicks); } _synDays++; } } } date = date.AddDays(1); } } if (_ticks.Any() && _ticks.Last().InsID == instrum.InsID) // тики внутри каждого инструмента отсортированы по времени, поэтому можно брать последний в списке и он будет последний по времени { if (!_insID_lastTick.ContainsKey(instrum.InsID)) { _insID_lastTick.Add(instrum.InsID, _ticks.Last()); } else // перестраховка { _insID_lastTick[instrum.InsID] = _ticks.Last(); } } } await Task.Run(() => { lock (_ticks) { _ticks = _ticks.OrderBy(t => t.Time).ToList(); int count = _ticks.Count; for (int i = 0; i < count; i++) { var tick = _ticks[i]; tick.TradeNo = i + 1; } } }); return(GetTicksCount()); }