← 戻る

Простой пример закачки истории тиков с финама или другого источника

Всем привет! Только начал разбираться с библиотекой, новичек в общем я. Можете написать простой рабочий пример(кусок кода) закачки данных с финама, ну или с другого источника за период ну пусть пару дней по инструменту LKOH. Ну или хотя бы вообще хоть какой-нибудь примерчик. Никак разобраться не получается. Заранее спасибо

このトピックは参考になりましたか?

トピックを共有

コメント (4)

ログイン または アカウントを作成, コメントを残すにはログインまたは新規登録してください

dron3333
dron3333 著者

Ребят, что никто не поможет?....

VassilSanych
VassilSanych

Загрузка из Гидры

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using StockSharp.Algo;
using StockSharp.Algo.Candles;
using StockSharp.Algo.Storages;
using StockSharp.BusinessEntities;
using StockSharp.Logging;
using Candle = VGn.Robot.Candle;

namespace VGn.Robot
{
	/// <summary>
	///  Класс предварительной подготовки данных
	/// </summary>
	public class DataLoader : BaseLogReceiver
	{
		LogManager logManager;
		IMarketDataStorage<Trade> tradesStorage;

		Security security;

		public DataLoader()
		{
			
			logManager = new LogManager();
			logManager.Listeners.Add(new FileLogListener(@"c:\candles.log"));
			logManager.Sources.Add(this);

			var path = Path.GetFullPath(@"c:\Hydra\");

			var storageRegistry = new StorageRegistry
			{
				// изменяем путь, используемый по умолчанию
				DefaultDrive = new LocalMarketDataDrive(path)
			};

			security = GenerateSecurity(); 

			tradesStorage = storageRegistry.GetTradeStorage(security);

		}


		public CandleSeries CreateTimeSeries(TimeSpan frameSize)
		{
			var candleFrame = "TimeFrameCandle";
			var candleFrameType = Type.GetType(string.Format("StockSharp.Algo.Candles.{0}, StockSharp.Algo", candleFrame), true);
			return new CandleSeries(
				candleFrameType, security, frameSize) { WorkingTime = ExchangeBoard.Forts.WorkingTime };
		}




		private static readonly string[] Mounths = { "H", "M", "U", "Z", }; // последовательность важна для правильной генерации имен фьючерсов
		public const int FIRST_YEAR = 2009;


		//todo: загрузка таблицы дат экспирации из файла
		public Dictionary<int, List<int>> FortsExpirationTable =
			new Dictionary<int, List<int>>()
			{
				{9, new List<int> {13,11,14,14}},
				{10, new List<int> {12,11,15,15}},
				{11, new List<int> {15,15,15,15}},
				{12, new List<int> {15,15,17,17}},
				{13, new List<int> {15,17,16,16}},
				{14, new List<int> {17,16,15,15}},
				{15, new List<int> {16,15,15,15}},
			};


		/// <summary>
		///  Создание склеенного фьючерса RI
		/// </summary>
		/// <returns></returns>
		public ContinuousSecurity GenerateSecurity()
		{
			var prefix = "RI";
			var securityName = prefix + "@CONTINIOUS";
			var result = new ContinuousSecurity
			{
				Id = securityName,
				Code = securityName,
				Name = "ContinuousSecurity for " + securityName,
				Board = ExchangeBoard.Forts,
			};
			for (var year = FIRST_YEAR; year < 2015; year++)
			{
				for (var i = 0; i < 4; i++)
				{
					var yearPart = year % 10;      // тут получаем последнюю цифру года
					var mounth = i * 3 + 3;
					var mounthPart = Mounths[i]; // тут выбирается индекс, показывающий месяц

					var id = prefix + mounthPart + yearPart + "@FORTS";
					var code = prefix + "-" + (yearPart) + "." + (mounth);
					var security = new Security
					{
						Id = id,
						Code = code,
						Name =
								"ContinuousSecurity for " + prefix + " expiration in " + mounth + "." +
								year,
						Board = ExchangeBoard.Forts,
					};
					var expiration = new DateTime(year, mounth, FortsExpirationTable[year - 2000][i]);
					result.ExpirationJumps.Add(security, expiration);
				}
			}
			return result;
		}


		/// <summary>
		/// Трансформация свечей в короткую форму 
		/// </summary>
		public IEnumerable<Candle> TransformCandles(CandleSeries series, DateTime startTime, DateTime stopTime)
		{
			var trades = tradesStorage.Load(startTime, stopTime);
			var id = 1;
			foreach (var candle in trades.ToCandles(series))
			{
				var mycandle = new Candle
				{
					Close = candle.ClosePrice,
					High = candle.HighPrice,
					Id = id++,
					Low = candle.LowPrice,
					Open = candle.OpenPrice,
					Volume = candle.TotalVolume,
					Time = candle.CloseTime
				};
				yield return mycandle;
				//CandleList.Add(mycandle);
			}
			//this.AddInfoLog("Количество свечек {0}", CandleList.Count);
			
		}



		/// <summary>
		///  Загрузка готовых свечек из файла
		///  с целью исключения повторного формирования списка свечей
		/// </summary>
		/// <param name="fileName"></param>
		/// <returns></returns>
		public static  T GetFromFile<T>(string fileName) where T : class
		{
			if (!File.Exists(fileName))
				return null;

			//if (File.GetLastWriteTime(fileName).Date.AddDays(1) < DateTime.Now)
			//{
			//	File.Delete(fileName);
			//	return null;
			//}

			using (Stream stream = File.Open(fileName, FileMode.Open))
			{
				var bin = new BinaryFormatter();
				var list = (T)bin.Deserialize(stream);
				return list;
			}
		}


		/// <summary>
		///  Сохранение готовых свечек в файл
		///  с целью исключения повторного формирования списка свечей в тот же день 
		/// </summary>
		/// <param name="fileName"></param>
		/// <param name="list"></param>
		public static void WriteToFile<T>(string fileName, T list)
		{
			var v = Path.GetPathRoot(fileName);
			var c = Directory.Exists(v);
			using (Stream stream = File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.Read))
			{
				var bin = new BinaryFormatter();
				bin.Serialize(stream, list);
			}
		}


	}
}
dron3333
VassilSanych
VassilSanych

Загрузка вчерашних данных для торговли на Квике. Код старый - не факт, что работает с новым API.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Ecng.Common;
using StockSharp.Algo;
using StockSharp.Algo.Candles;
using StockSharp.Algo.Candles.Compression;
using StockSharp.Algo.History;
using StockSharp.Algo.History.Finam;
using StockSharp.Algo.History.Rts;
using StockSharp.Algo.Storages;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Logging;

namespace VgnRobot.RobotEngine
{
	/// <summary>
	///		Базовый класс для свечных стратегий
	/// </summary>
	public abstract class CandleStrategyBase : Strategy
	{
		public ITimeCheckProvider TimeCheckProvider { get; set; }
		public IStopProvider StopProvider { get; set; }


		//protected StopOrdersChecker stopOrdersChecker;
		public readonly SyncObject Locker = new SyncObject();
		
		protected CandleStrategyBase()
		{
			// добавление отдельного логирования стратегии
			LogManager = new LogManager();
			ExchangeBoard.Forts.ApplyHolidays2013();
			//ExchangeBoard.Forts.ApplyHolidays2012();
		}

		private void InitSettings()
		{
			decimal minStepPrice;
			MinStepPriceSetting = Settings.TryGetProperty("MinStepPrice", out minStepPrice, this)
															? minStepPrice
															: (decimal?)null;
		}

		private decimal? MinStepPriceSetting { get; set; }





		/// <summary>
		///  Настройки стратегии
		///	 (для доступа к общим настройкам из родителького класса)
		/// </summary>
		public System.Configuration.SettingsBase Settings { get; set; }

		public CandleSeries Series { get; private set; }
		public virtual string Description { get { return Name; } }
		public ITraderBuilder TraderBuilder { get; set; }
		public IPortfolioSelector PortfolioSelector { get; set; }
		public ISecuritySelector SecuritySelector { get; set; }
		public IVolumeSizer VolumeSizer { get; set; }
		public IHistoryCandleProvider HistoryCandleProvider { get; set; }
		public ISettingsProvider SettingsProvider { get; set; }

		/// <summary>
		///  Движок создания заявок
		/// </summary>
		public IOrderHelper OrderHelper { get; set; }
		
		public Unit PriceDelta { get; set; }

		public Type CandleFrameType { get; set; }
		/// <summary>
		///  Текстовая обёртка CandleFrameType. Работает в обе стороны.
		/// </summary>
		public string CandleFrame
		{
			get
			{
				return CandleFrameType.Name;
			} 
			set
			{
				CandleFrameType = Type.GetType(string.Format("StockSharp.Algo.Candles.{0}, StockSharp.Algo", value), true);
			}
		}
		public object FrameSize { get; set; }


		DateTime _strategyStartTime;


		//public IList<Candle> GetHistoryTrades(DateTime beginDate, DateTime endDate)
		//{
		//	string uri = GetInstrumentUrl(beginDate, endDate);
		//	WebRequest request = WebRequest.Create(uri);
		//	using (StreamReader sr = new StreamReader(request.GetResponse().GetResponseStream()))
		//	{
		//		IList<Candle> result = new CandleReader().ReadCandles(sr);
		//		return result;
		//	}
		//}


		#region AddHistoryCandles Загрузка исторических свечек за прошлый день

		/// <summary>
		///  Класс-затычка для хранилища истории
		/// </summary>
		private class DumbSecurityStorage : ISecurityStorage
		{
			private Security _security;

			public Security LoadBy(string fieldName, object fieldValue)
			{
				return _security;
			}

			public void Save(Security security)
			{
				_security = security;
			}
		}


		Trade ParseTrade(string finamString)
		{
				var culture = new CultureInfo(System.Threading.Thread.CurrentThread.CurrentCulture.Name) { NumberFormat = { NumberDecimalSeparator = "." } };

				var parts = finamString.Split(',');
				var trade = new Trade
					{
						Time = DateTime.ParseExact(parts[0] + parts[1], "yyyyMMddHHmmss", culture),
						Price = decimal.Parse(parts[2], culture),
						Volume = decimal.Parse(parts[3], culture),
						Id = long.Parse(parts[4]),
						Security = Security
					};
				return trade;
				//{
				//	//<DATE>,<TIME>,<LAST>,<VOL>,<ID>
				//	Time = DateTime.ParseExact(parts[0] + parts[1], "yyyyMMddHHmmss", CultureInfo.InvariantCulture),
				//	Price = decimal.Parse(parts[2], CultureInfo.CurrentCulture),
				//	Volume = decimal.Parse(parts[3], CultureInfo.CurrentCulture),
				//	Id = long.Parse(parts[4]),
				//	Security = Security,
				//};
		}


		/// <summary>
		///  Получение сделок из файла, загруженного вручную с Финама
		/// </summary>
		/// <param name="filePath"></param>
		/// <returns></returns>
		IEnumerable<Trade> GetTradesFromTxt(string filePath)
		{
			var tradeHistory = new List<Trade>();
			if (!File.Exists(filePath))
			{
				return tradeHistory;
			}
			var history = File.ReadAllLines(filePath).Select(ParseTrade);
			return history;
		}


		/// <summary>
		///  Получение сделок с сайта Финама
		/// </summary>
		/// <param name="date"></param>
		/// <returns></returns>
		IEnumerable<Trade> GetTradesFromFinam(DateTime date)
		{
			var storage = new DumbSecurityStorage();
			storage.Save(Security);
			var source = new FinamHistorySource(storage) { DumpFolder = GetTempPath() };
			long finamMarketId;
			Settings.TryGetProperty("HistoryFinamMarketId", out finamMarketId);  //14 
			long finamSecurityId;
			Settings.TryGetProperty("HistoryFinamSecurityId", out finamSecurityId);  //82813; 
			Security.ExtensionInfo["FinamMarketId"] = finamMarketId;
			Security.ExtensionInfo["FinamSecurityId"] = finamSecurityId;
			return source.GetTrades(Security, date);
		}


		/// <summary>
		///  Получение сделок с FTP RTS
		/// </summary>
		/// <param name="date"></param>
		/// <param name="loadEvening"></param>
		/// <returns></returns>
		IEnumerable<Trade> GetTradesFromRts(DateTime date, bool loadEvening = false)
		{
			var storage = new DumbSecurityStorage();
			storage.Save(Security);
			var source = new RtsHistorySource(storage) { DumpFolder = GetTempPath(), LoadEveningSession = loadEvening};
			var trades = new Dictionary<Security, IList<Trade>>();
			source.LoadTrades(date, trades);
			if (!trades.ContainsKey(Security))
				throw new ApplicationException("Не получены данные за прошлый день");
			return trades[Security];
		}


		/// <summary>
		///  Папка временных файлов для всех способов загрузки
		/// </summary>
		/// <returns></returns>
		private string GetTempPath()
		{
			var tempPath = Path.Combine(@"E:\TradeStorage\", "TemporaryFiles");

			if (!Directory.Exists(tempPath))
				Directory.CreateDirectory(tempPath);

			return tempPath;
		}


		/// <summary>
		///  Получение даты прошлого дня с учётов выходных и праздников 
		/// </summary>
		/// <param name="date"></param>
		/// <returns></returns>
		DateTime GetLastDateBefore(DateTime date)
		{
			do
			{
				date = date.AddDays(-1);
				if (ExchangeBoard.Forts.WorkingTime.IsTradeDate(date, true))
					return date;
			} while (true);
		}


		protected TradeStorageCandleBuilderSource HistorySource;

		/// <summary>
		///  Добавление в список свечей данных из хранилища
		/// </summary>
		private void AddHistoryCandles()
		{
			try
			{
				this.AddDebugLog("Загрузка сделок за прошлый день");
				var storageRegistry = new StorageRegistry();
				string tradeStoragePath;
				Settings.TryGetProperty("HistoryTradeStoragePath", out tradeStoragePath);
				((LocalMarketDataDrive) storageRegistry.DefaultDrive).Path = tradeStoragePath;
				var storage = storageRegistry.GetTradeStorage(Security);

				var thisDate = LoggingHelper.Now.Date;
				var lastDate = GetLastDateBefore(thisDate);

				string historySource;
				Settings.TryGetProperty("HistorySource", out historySource);
				switch (historySource)
				{
					case "RTS":
						if (!storage.Dates.Contains(thisDate))
						{
							this.AddDebugLog("Загрузка сделок с RTS");
							var trades = GetTradesFromRts(lastDate, true);
							//
							storage.Save(trades.Where(t => t.Time > lastDate && t.Price > 0));
							//пропуск закачки более старых (нужна закачка целыми днями) и игнорирование ошибки данных
							// на ftp ртс данные выложены по сессиям с 19.00 до 19.00

							//trades = GetTradesFromRts(thisDate, true);
							//storage.Save(trades.Where(t => t.Time < thisDate && t.Price > 0));
							//пропуск закачки сегодняшних и игнорирование ошибки данных
							//todo: обработка ошибок закачки (стратегия останавливается)
						}
						break;
					case "Finam":
						if (!storage.Dates.Contains(lastDate))
						{
							this.AddDebugLog("Загрузка сделок с Финама");
							var trades = GetTradesFromFinam(lastDate);
							storage.Save(trades);
						}
						break;
					default:
						if (!storage.Dates.Contains(lastDate))
						{
							this.AddDebugLog("Загрузка сделок из файла");
							//var trades = GetTradesFromTxt(@"E:\Downloads\RIH3_130312_130312.txt");
							var trades = GetTradesFromTxt(string.Format(
								"{0}{1}_{2}_{2}.txt",
								tradeStoragePath, Security.Code, lastDate));
							storage.Save(trades);
						}
						break;
				}

				// берём только сделки раньше тех, что есть в таблице
				var lastTimeSource = Trader.Trades.Select(t => t.Time).ToArray();
				var lastTime = lastTimeSource.Any() ? lastTimeSource.Min() : thisDate;
				HistorySource = new TradeStorageCandleBuilderSource
					{
						StorageRegistry = storageRegistry,
						Filter = trade => trade.Time > lastDate && trade.Time < lastTime,
					};
				TraderBuilder.CandleManager.Sources.OfType<TickCandleBuilder>().Single().Sources.Add(HistorySource);
			}
			catch (Exception ex)
			{
				this.AddErrorLog(ex);
			}
		}


		/// <summary>
		///  Очистка памяти от истории за прошлый день.
		/// </summary>
		protected void DeleteHistory()
		{
			if (HistorySource == null)
				return;
			var source = HistorySource;
			HistorySource = null;
			TraderBuilder.CandleManager.Sources.OfType<TickCandleBuilder>().Single().Sources.Remove(source);
			source.Dispose();
			GC.Collect(2, GCCollectionMode.Forced);
		}

		#endregion

		//readonly object _candleProcessLocker = new object();
		protected override void OnStarted()
		{
			try
			{
				InitSettings();
				Trader = TraderBuilder.BuildTrader();
				OrderHelper = TraderBuilder.OrderHelper;
				if (Trader == null)
					throw new ApplicationException(string.Format("Отсутствует трейдер {0}.", TraderBuilder.Title));
				_strategyStartTime = Trader.GetMarketTime(ExchangeBoard.Forts.Exchange);

				Portfolio = PortfolioSelector.GetPortfolio(Trader);
				if (Portfolio == null)
					throw new ApplicationException(string.Format("Отсутствует портфель {0}.", PortfolioSelector.Title));

				Security = SecuritySelector.GetSecurity(Trader);
				if (Security == null)
					throw new ApplicationException(string.Format("Отсутствует инструмент {0}.", SecuritySelector.Title));
				Trader.RegisterSecurity(Security);

				Trader.RegisterMarketDepth(Security);

				if (VolumeSizer != null)
				{
					Volume = VolumeSizer.GetVolume(Portfolio, Security);
					this.AddInfoLog("Объем: {0}", Volume);
				}

				AddHistoryCandles();

				Series = new CandleSeries(
					CandleFrameType, Security, FrameSize) { WorkingTime = ExchangeBoard.Forts.WorkingTime };
					// Если Security - это WeightedIndexSecurity, то _series не заполняется

				Series
					.WhenCandlesFinished()
					.Do(CandleFinishedCall)
					.Sync(Locker)
					.Apply(this);

				TraderBuilder.CandleManager.Start(Series);

				base.OnStarted();

			}
			catch (Exception ex)
			{
				this.AddErrorLog(ex);
				Stop();
			}
		}


		public event Action<Candle> CandleFinished;

		/// <summary>
		///  Свеча сформирована
		/// </summary>
		/// <param name="candle"></param>
		private void CandleFinishedCall(Candle candle)
		{
			try
			{
				//todo: померять время
				ProcessCandle(candle);
				if (CandleFinished != null)
					CandleFinished(candle); // стратегия уже должна обработать все индикаторы
			}
			catch (Exception ex)
			{
				this.AddErrorLog(ex);
			}
		}


		protected override void OnStopping()
		{
			//todo: закрытие позиций

			if (Security != null)
				Trader.UnRegisterMarketDepth(Security);
		}


		protected override void OnStopped()
		{
			base.OnStopped();
		}


		protected virtual void ProcessCandle(Candle candle)
		{}

		private decimal _minStepPrice;
		/// <summary>
		///  Получение минимального лота из настроек, потому что соответствующее свойство Security иногда глючит
		/// </summary>
		public decimal MinStepPrice
		{
			get
			{
				if (_minStepPrice == 0)
				{
					_minStepPrice = MinStepPriceSetting != null
						? MinStepPriceSetting.Value
						: Security.MinStepPrice;
				}
				return _minStepPrice;
			}
		}


		/// <summary>
		///  Получение лучшей цены из стакана (цены изнутри спреда).
		/// </summary>
		/// <param name="direction"></param>
		/// <returns></returns>
		public decimal GetBestInnerPrice(OrderDirections direction)
		{
			var price = direction == OrderDirections.Buy
										? (Security.BestBid != null ? Security.BestBid.Price + MinStepPrice : 0)
										: (Security.BestBid != null ? Security.BestAsk.Price - MinStepPrice : 0);
			return price;
		}


		/// <summary>
		///  Создание и регистрация лимитных заявок в рамках стратегии
		/// </summary>
		/// <param name="direction"></param>
		/// <param name="volume"></param>
		protected void SendStrategyOrders(OrderDirections direction, decimal volume)
		{
			try
			{
				CancelActiveOrders(o => o.Type == OrderTypes.Limit);

				//while (Position != Portfolio.GetPosition() || Orders.Any(o => o.State == OrderStates.Active))
				//{
				//	this.AddWarningLog("* Разбег позиций перед сделкой: PositionManager {0} Trader {1}",
				//		Position, Portfolio.GetPosition());
				//	Thread.Sleep(100);
				//}

				var price = GetBestInnerPrice(direction);
				var order = OrderHelper.CreateLimitOrder(
						Security,
						direction,
						volume,
						price,
						null);

				var newTradesRule = order.WhenNewTrades();
				newTradesRule.Do(OnStrategyTrades).Sync(Locker).Apply();

				TimeCheckProvider.CurrentWaiting = 0;
				this.AddInfoLog(
					"* Новая заявка: Объём {0} Цена {1} Направление {2}",
					volume, price, direction);
				RegisterOrder(order);
			}
			catch (Exception ex)
			{
				this.AddErrorLog("* Ошибка регистрации заявки: {0}", ex);
			}

		}


		/// <summary>
		///  Обработка получения новых сделок
		/// </summary>
		/// <param name="trades"></param>
		private void OnStrategyTrades(IEnumerable<MyTrade> trades)
		{
			//todo: логирование новых сделок здесь?
			// возможно стоит создать некий буфер, чтобы логировать и здесь и по событию получения сделок (здесь, наверное, быстрее)
			StopProvider.AddStops(trades);
		}





		public LogManager LogManager { get; set; }

		public IChartPresenter ChartPresenter { get; set; }
	}
}
dron3333
dron3333
dron3333 著者

Спасибо большое вам! Буду разбираться...