Михаил,
Создал MSSQL2008 базу trading на основе trading.sql из 3.0.1
При загрузке плагинов получил исключение
Гидра 22:53:28.7968750 System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: The stored procedure 'MarketDataSourceSettings_Create' doesn't exist.
Смею предположить, что trading.sql не соответствует сборке 3.0.1
Перед этим были аналогичная ошибка с MarketDataSourceSettings_ReadByIDSourceId, я нашел в БД процедуру с слегка отличным именем MarketDataLoaderSettings_ReadByLoaderId и переименовал.
С уважением.
Comentarios (23)
Iniciar sesión o Crear cuenta, Inicie sesión o regístrese para dejar un comentario
Так и есть.
выложите?
[3.0.2]
Действия: 0. Создал БД со скриптом trading.sql из 3.0.2
В Ecng.Trading.Hydra.Finam.FinamSecurityStorage.Save(Security) поставил брекпойнт Security=TESTESSR, Exchange=Тестовая биржа
Руками создал в Exchange Тестовая биржа и ММВБ в результате Hydra скачала 3000 c чем-то security. Значит, проблема в отсутствии записей в Exchange.
Посмотрел базу получилось 314 security из ММВБ и 3304 из Тестовая биржа
Но в окне "Инструменты" они не появились, какие бы фильтры я не выбирал.
Далее, я поставил источнику "РТС" и "Finam" IsEnabled=true, working from=0:0:0, working to=23.59.59.
и нажал "Старт".
В итоге в логе получил
Тут сразу две проблемы - одна с передачей null в FinamTradeSource.Load (при загрузке через Finam) вторая, видимо, снова с отсутствующей записью в Exchange (при загрузке через РТС)
После этого всего я закрыл Hydra. Когда заново запустил получил на старте
Это уже вне моего какого бы то понимания, потому что это похоже на stored procedure .net, в чем я слабо разбираюсь, особенно без исходников, но чувствуется что Ecng.Serialization и Ecng.Data вещи нетривиальные ;)
Есть догадка, что Ecng.Trading.Hydra.MainWindow.FillSecurities() загружает объекты из таблицы Exchange которые я руками добавил и скорее всего некорректно (все поля кроме Name оставил пустыми)
В общем, похоже дело в создании Exchange, но я не знаю толи они должны автоматически создаваться кодом, толи их создание должно быть в trading.sql.
Кроме того в trading.sql обнаружил в начале явный CREATE DATABASE с абсолютными путями. Мне кажется создать базу должен пользователь сам, а в скрипте должны инициализироваться все объекты БД.
С уважением.
Да, в PageLoad косяк. Должно выглядеть так:
С биржами багу исправил.
Надо ввести хоть один символ из названия в поле в левом верхнем углу.
CREATE PROCEDURE [dbo].[PageSelect] @table nvarchar, @startIndex [bigint], @count [bigint], @orderByColumn nvarchar = null, @columns nvarchar = null, @filter nvarchar = null, @param1 [sql_variant] = null, @param2 [sql_variant] = null, @param3 [sql_variant] = null, @param4 [sql_variant] = null, @param5 [sql_variant] = null, @param6 [sql_variant] = null, @param7 [sql_variant] = null, @param8 [sql_variant] = null, @param9 [sql_variant] = null, @param10 [sql_variant] = null AS EXTERNAL NAME [Ecng.Data.SqlServer].[Ecng.Data.SqlServer.SqlExtendedProcedures].[PageSelect]
System.Xml.XmlException: Root element is missing. at System.Xml.XmlTextReaderImpl.Throw(Exception e) at System.Xml.XmlTextReaderImpl.ThrowWithoutLineInfo(String res) at System.Xml.XmlTextReaderImpl.ParseDocumentContent() at System.Xml.XmlTextReaderImpl.Read() at System.Xml.Linq.XDocument.Load(XmlReader reader, LoadOptions options) at System.Xml.Linq.XDocument.Load(XmlReader reader) at Ecng.Serialization.XmlSerializer
1.Deserialize(Stream stream, FieldCollection fields, SerializationItemCollection source) at Ecng.Serialization.Serializer1.Deserialize(Stream stream, SerializationItemCollection source) at Ecng.Data.Database.GroupSource(IEnumerable1 fields, SerializationItemCollection input, IEnumerable1 innerSchemaNameOverrides) at Ecng.Data.Database.GetOrAddCache[TEntity](SerializationItemCollection input) at Ecng.Data.Database.Read[TEntity](DatabaseCommand command, SerializationItemCollection input) at Ecng.Data.Database.Read[TEntity](SerializationItemCollection by) at Ecng.Data.Database.Read[TEntity](SerializationItem by) at Ecng.Data.Database.Read[TEntity](Object id) at Ecng.Data.Database.Ecng.Serialization.IStorage.GetById[TEntity](Object id) at Ecng.Serialization.RelationSingleFieldFactory2.OnCreateInstance(ISerializer serializer, TSource source) at Ecng.Serialization.FieldFactory2.OnCreateInstance(ISerializer serializer, Object source) at Ecng.Serialization.FieldFactory.CreateInstance(ISerializer serializer, SerializationItem source) at Ecng.Serialization.Serializer1.Deserialize(SerializationItemCollection source, FieldCollection fields, T graph) at Ecng.Data.Database.<>c__DisplayClass221.<GetOrAddCacheTable>b__1d() at Ecng.Data.Database.AddCache[TEntity](TEntity entity, String key, Object id, SerializationItemCollection source, Boolean newEntry, Action action) at Ecng.Data.Database.GetOrAddCacheTable[TEntity](SerializationItemCollection table) at Ecng.Data.Database.ReadAll[TEntity](DatabaseCommand command, SerializationItemCollection input) at Ecng.Data.HierarchicalDatabase.ReadAll[TEntity](DatabaseCommand command, SerializationItemCollection source) at Ecng.Data.Database.ReadAll[TEntity](Int64 startIndex, Int64 count, Field orderBy, SortDirection direction) at Ecng.Data.Database.Ecng.Serialization.IStorage.GetGroup[TEntity](Int64 startIndex, Int64 count, Field orderBy, SortDirection direction) at Ecng.Serialization.RelationManyList1.OnGetGroup(Int64 startIndex, Int64 count, Field orderBy, SortDirection direction) at Ecng.Data.HierarchicalPageLoadList1.OnGetGroup(Int64 startIndex, Int64 count, Field orderBy, SortDirection direction) at Ecng.Serialization.RelationManyList1.ReadAll(Int64 startIndex, Int64 count, Field orderBy, SortDirection direction) at Ecng.Serialization.RelationManyList1.GetRange(Int64 startIndex, Int64 count, String sortExpression, SortDirection directions) at Ecng.Collections.BaseListEx1.GetRange(Int64 startIndex, Int64 count) at Ecng.Serialization.RelationManyList1.get_Count() at Ecng.Serialization.RelationManyList1.RelationManyListEnumerator.ProcessMove(Boolean& canProcess) at Ecng.Collections.BaseEnumerator2.System.Collections.IEnumerator.MoveNext() at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() at System.Linq.Enumerable.WhereEnumerableIterator1.MoveNext() at Ecng.Collections.CollectionHelper.AddRange[T](ICollection1 source, IEnumerable1 items) at Ecng.Trading.Hydra.MainWindow.FillSecurities() in D:\SS\Sources\Hydra\Hydra\MainWindow.xaml.cs:line 155 at Ecng.Trading.Hydra.MainWindow..ctor() in D:\SS\Sources\Hydra\Hydra\MainWindow.xaml.cs:line 64 --- End of inner exception stack trace --- at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck) at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean fillCache) at System.RuntimeType.CreateInstanceImpl(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean fillCache) at System.Activator.CreateInstance(Type type, Boolean nonPublic) at System.Windows.Markup.BamlRecordReader.CreateInstanceFromType(Type type, Int16 typeId, Boolean throwOnFail) --- End of inner exception stack trace --- at System.Windows.Markup.XamlParseException.ThrowException(String message, Exception innerException, Int32 lineNumber, Int32 linePosition, Uri baseUri, XamlObjectIds currentXamlObjectIds, XamlObjectIds contextXamlObjectIds, Type objectType) at System.Windows.Markup.XamlParseException.ThrowException(ParserContext parserContext, Int32 lineNumber, Int32 linePosition, String message, Exception innerException) at System.Windows.Markup.BamlRecordReader.ThrowExceptionWithLine(String message, Exception innerException) at System.Windows.Markup.BamlRecordReader.CreateInstanceFromType(Type type, Int16 typeId, Boolean throwOnFail) at System.Windows.Markup.BamlRecordReader.GetElementAndFlags(BamlElementStartRecord bamlElementStartRecord, Object& element, ReaderFlags& flags, Type& delayCreatedType, Int16& delayCreatedTypeId) at System.Windows.Markup.BamlRecordReader.BaseReadElementStartRecord(BamlElementStartRecord bamlElementRecord) at System.Windows.Markup.BamlRecordReader.ReadElementStartRecord(BamlElementStartRecord bamlElementRecord) at System.Windows.Markup.BamlRecordReader.ReadRecord(BamlRecord bamlRecord) at System.Windows.Markup.BamlRecordReader.Read(Boolean singleRecord) at System.Windows.Markup.TreeBuilderBamlTranslator.ParseFragment() at System.Windows.Markup.TreeBuilder.Parse() at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream) at System.Windows.Application.LoadBamlStreamWithSyncInfo(Stream stream, ParserContext pc) at System.Windows.Application.LoadComponent(Uri resourceLocator, Boolean bSkipJournaledProperties) at System.Windows.Application.DoStartup() at System.Windows.Application.<.ctor>b__0(Object unused) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)Ставьте это в код Гидры (главное окно, конструктор) и запустите:
Теперь процедуру Exchange_Create не находит.
Сорри, описался:
[3.0.2]
Пробовал загрузить Security из хранилища
получил Procedure or function 'Security_ReadAll' expects parameter '@StartIndex', which was not supplied.
Странно тк, в гидре похожая вещь в FillSecurities проходит успешно
В чем может быть дело?
[3.0.3]
Хочу загрузить все трейды из ITradingSource.
А какой диапазон дат ставить?
Никакого API определяющего диапазон дат для загруженных в хранилище данных нет
Предлагаю добавить метод ITradingSource.GetTradesHistoryRange(Security s) который вернет Range<DateTime> c минимальной и максимальной датами загруженных данных.
Есть, прочитайте документацию про Storage API.
Михаил,
Наверноя слепой ;)
Подскажите пожалуйста класс и метод?
Я смотрел в ITradingStorage, TradingStorage и в Security но ничего похожего на MinDataDate/MaxDataDate не нашел :(
C уважением.
Я не увидел что нужны границы... Вообще так ITradingStorage.LoadTrades(Date,Date). А чтобы максимум и минимум. Я такое не делал.
Было бы неплохо иметь такие функции чтобы знать сколько данных загружено.
Еще попытался тестировать гидру со SmartCom
инструменты обновились нормально. выставил RIH1 чтобы сделки и стаканы грузились через Smart. Нажал Старт получил
А идентификатор точно Смартовский у инструмента?
Идентфкатор был финамовский похоже. С пустой базой наполненной инструментами из смарта загрузка стакана пошла.
Вообще, как предполагается данные из разных источников совмещать?
В базе после обновления с РТС и со Смарта есть такие вот записи
Id, Name, Code, Class RTS-12.10_FT, RTS-12.10, RIZ0, RTS_FUT - фьючерс загружен из смарта
RTS-12.10, RIZ0, RTS-12.10, пусто - фьючерс загружен из РТС
из квика не пробовал. Там будет может третий идентификатор.
Однако на лицо то, что Name и Code в смарте и РТСе перепутаны. Я полагаю должно быть Code=RIZ0, Name=RTS-12.10
еще я могу ошибаться, но идентификатор Id у Security может совпадать для смартовских даннх и РТСовских (финамовских). ТОгда загруженные через эти разные источники данные могут перепутаться (они же запишутся в одну и ту же директорию) Я думаю это неправильно (перепутывание данных)
В идеале (для меня) в таблице Security не должно быть повторов одного инструмента под разными псевдонимами (в данном случае RTS-12.10_FT и RTS-12.10). Это бы упрощало в стратегии жизнь. А вот данных для одного инструмента может быть несколько вариантов - с финама, со смарта, еще откуда-то. Т.е. каждый источник - свои данные. И хранятся они в разных папках, например FINAM/RTS-12.10/дата и SMART/RTS-12.10/дата.
Сразу вознкает вопрос, а какие данные использовать при прогоне стратегии? Оптимальным мне кажется сделать специальный алгоритм DataSelectionAlgorithm который будет выбирать для конкретной Security и конкретного дня, какие данные использовать.
Например алгоритм мог бы действовать так:
КакиеДанныеПоТиковымСделкамИспользовать(RIZ0, 1 апреля 2010г) if(есть_накопленные_данные_Смарта(RIZ0, 1 апреля 2010г) return использовать данные смарта if(есть_данные_РТС(RIZ0, 1 апреля 2010г)) return использовать данные РТС.
КакиеДанныеПоСтакануИспользовать(RIZ0, 1 апреля 2010г) if(есть_накопленные_данные_Смарта(riz0, 1 апреля 2010г) return использовать_стакан_смарта if(нет никаких данных) return использовать_генератор_стакана.
Тут есть еще одна идея - в данных может быть мусор. Можно озаботиться алгоритмом проверки-фильтрации данных. Это будет как бы еще один MarketDataSource.
Что скажете?
Да, поменял местами в коде. В БД надо так же будет заменить после обновления.
Это как раз правильно, когда инструменты едины для разных источников. Не логично, когда одни и те же маркет данные грузятся по разным источникам.
Согласен. Варианты решения?
А вот тут не согласен. Я понимаю, когда стаканы и тики грузятся для одного инструмента по разным источникам. Тогда они просто в одну и ту же папку попадают. Но зачем делать еще группировку по источникам?
Вот поэтому, понятие источника не должно вылезать дальше Гидры. ITradingStorage глубоко наплевать откуда данные накачали. Все что она должна делать, отдавать данные когда у нее просят. Хотят тики за период такой-то - получите. Стаканы - да бога ради.
У Смарта код и имя расположена правильно.
Допустим ситуация. С 1 апреля по 1 мая я скачивал LKOH финамом. С 1 мая поставил его на скачивание смартом. 1 июня я пропустил день скачивания данных смартом. хочу финамом подгрузить данные. Поставлю инструменту источник финам. Гидра посмотрит что по LKOH финамом скачивали последний раз 30 апреля. И скачает месяц данных с 1 мая по 1 июня перезаписав все смартовские данные. А я хотел всего то 1 день скачать.
Я приводил пример алгоритма выбора данных который могла бы использовать ITradingStorage для выбора данных из нескольких источников.
Напишите доп настройки для ограничения по датам. Гидра не умеет скачивать за конкретные период и только.
Да, наверное так и сделаю. Надо у Смарта в Security.Extension положить его идентификатор.
Там же про код клиента речь идет.
Качество данных нужно анализировать до скачивания. Для этого можно гидрой накачать в разные директории тики и потом сравнить, какой в итоге источник лучше. Или нет?
Закончил с идентификаторами, чтобы схема была единой. Малой кровью обойти не удалось - для Гидры нужно будет менять все идентификаторы. А следовательно, и сами папки. Теперь схема такая. Security.Id == Code@RTS для РТС биржи, и Code@Class для всего остального. Соответственно, и папки теперь будут называться к примеру не RTS-3.11 а RIH1@RTS, не LKOH, а LKOH@EQBR. И так для всего - QuikTrader, SmartTrader, Hydra... Выложу в понедельник, надо проверить на реале. По Гидре наверное будет проще все грохнуть (БД + файлы). Скаченные данные только не нужно удалять. По идее, Гидра за день пару лет по всей бирже успевает обрабатывать.