Блог им. AGorchakov

Код для формирования минуток из таблицы всех сделок квика для спота

Порядок действий

1. Формируем в квике таблицу всех сделок со следующими параметрами

Код для формирования минуток из таблицы всех сделок квика для спота

Фильтром отбираем нужные инструменты.

2. Скачиваем из Интернета свободно распространяемый DDE сервер от Морошкина с прилагаемыми dll.
3. В соответствующих местах кода заменяем код на вот этот

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Timers;
using System.Threading;
using XlDde;

namespace ConsoleApplication2
{
class Program
{
const string service = «myDDE»;
const string candleSPOT = «SPOT»;


static void Main(string[] args)
{

using (XlDdeServer server = new XlDdeServer(service))
{

server.AddChannel(candleSPOT, new SPOTChannel());
server.Register();

Console.WriteLine(«DDE server ready. Press Enter to exit.\n\n»);
Console.ReadLine();
}



}
}


// **********************************************************************
// * Классы DDE каналов с обработчиками данных *
// **********************************************************************


class SPOTChannel: XlDdeChannel
{
//static int time2 = 1000;
static int em = 7;
static int m = 1200;
static int[] NM = new int[em];
static int NMM = 0;
static int LastMinute = 0;
static int mm = 1638400;
static double[] Price_trade = new double[mm];
string[] EM_trade = new string[mm];
static int[] Time_trade_I = new int[mm];
static int[] Volume_trade = new int[mm];
static int[,] Time = new int[em,m];
static double[,] O = new double[em,m];
static double[,] H = new double[em,m];
static double[,] L = new double[em,m];
static double[,] C = new double[em,m];
static double[,] V = new double[em,m];

protected override void ProcessTable(XlTable xt)
{

//int time3 = 1000;
int[] nach = new int[em];
int nach1 = 0;
int i = 0;
int j = 0;
int s = 0;
int curHour = 0;
int curMin = 0;
int curDay = 0;
int curSec = 0;
int curDay_1 = 0;
string name;
string[] bf;
string[] EM = new string[em];
DateTime moment;
string[] Time_trade = new string[mm];

name = @«D:\Day2\Tiker_1.txt»;
try
{
StreamReader g = new StreamReader(name);

while ((name = g.ReadLine()) != null)
{
bf = name.Split(',');
for (i = 0; i < em; i++) EM[i] = Convert.ToString(bf[i]);

}
g.Close();
}
catch (FileNotFoundException e)
{
Console.WriteLine(e.Message);
Console.WriteLine(«Проверьте правильность имени файла!!!»);
}

catch (Exception e)
{
Console.WriteLine(«Ошибка:» + e.Message);
}


for (int row = 0; row < xt.Rows; row++)
{
for (int col = 0; col < xt.Columns; col++)
{
xt.ReadValue();
if (col == 0) Time_trade[row] = xt.StringValue;
if (col == 1) EM_trade[NMM] = xt.StringValue;
if (col == 2) Price_trade[NMM] = xt.FloatValue;
if (col == 3) Volume_trade[NMM] = xt.FloatValue;
moment = Convert.ToDateTime(Time_trade[row]);
int Hour = moment.Hour; int M = moment.Minute; int S = moment.Second;
Time_trade_I[NMM] = Hour * 100 + M;
}

curHour = DateTime.Now.Hour;
curMin = DateTime.Now.Minute;
curDay = curHour * 100 + curMin;

 

if (curDay < 1900) { if (Time_trade_I[LastMinute] == 1839 && (Time_trade_I[LastMinute] != Time_trade_I[NMM]) && s == 1) { LastMinute = NMM; for (i = 0; i < em; i++) NM[i]++; s = 0; } }


if ((Time_trade_I[LastMinute] != Time_trade_I[NMM]) && (NMM != LastMinute))
{

for (j = 0; j < em; j++)
{ Time[j, NM[j]] = Time_trade_I[LastMinute]; C[j, NM[j]] = 0; H[j, NM[j]] = 0; L[j, NM[j]] = 1000000; O[j, NM[j]] = 0; V[j,NM[j]]=0;}

for (i = LastMinute; i < NMM; i++)

{

for (j = 0; j < em; j++)
{

if (EM[j] == EM_trade[i])
{
if (O[j, NM[j]] == 0) { O[j, NM[j]] = Price_trade[i]; H[j, NM[j]] = Price_trade[i]; L[j, NM[j]] = Price_trade[i]; C[j, NM[j]] = Price_trade[i]; V[j,NM[j]]=Volume_trade[i];}

else { H[j, NM[j]] = Math.Max(H[j, NM[j]], Price_trade[i]); L[j, NM[j]] = Math.Min(L[j, NM[j]], Price_trade[i]); C[j, NM[j]] = Price_trade[i]; V[j,NM[j]]+=Volume_trade[i];}
}

}

}

for (j = 0; j < em; j++) { if (O[j, NM[j]] != 0) NM[j]++; }
LastMinute = NMM;

curHour = DateTime.Now.Hour;
curMin = DateTime.Now.Minute;
curDay = curHour * 100 + curMin;

if (curMin == 0) curDay = (curHour — 1) * 100 + 60;


for (j = 0; j < em; j++)
{
nach1 = 0;

for (i = 1; i < NM[j]; i++) { if (Time[j,i] < Time[j,i — 1]) nach1 = i; }

if (curDay < 1849) { if (Time[j, nach1] == 959) nach[j] = nach1 + 1; else nach[j] = nach1; }

if (Time[j,NM[j] — 1] + 1 >= curDay || Time[j,NM[j] — 1] + 1 == 1400)
{


Console.WriteLine("{0,6},{1,6},{2,6},{3,6},{4,6},{5,6},{6,6},{7,6}", EM[j], Time[j,NM[j] — 1] * 100, O[j,NM[j] — 1], H[j,NM[j] — 1], L[j,NM[j] — 1], C[j,NM[j] — 1], Time[j,NM[j] — 1] + 1, curDay);


// Вдогонку напишем информацию о состоянии канала

Console.WriteLine("\nSPOT IsConnected: {0}, Data received: {1}\n", this.IsConnected, this.DataReceived);
}
}
}

curHour = DateTime.Now.Hour;
curMin = DateTime.Now.Minute;
curSec = DateTime.Now.Second;

curDay = curHour * 100 + curMin;
curDay_1 = curHour * 10000 + curMin * 100 + curSec;

if (curDay < 1900)
{

if (Time_trade_I[LastMinute] == 1839 && curDay < 1842 && curDay_1 > 183855)
{
for (j = 0; j < em; j++)
{ Time[j, NM[j]] = Time_trade_I[LastMinute]; C[j, NM[j]] = 0; H[j, NM[j]] = 0; L[j, NM[j]] = 1000000; O[j, NM[j]] = 0; V[j,NM[j]]=0; }

for (i = LastMinute; i < NMM; i++)

{

for (j = 0; j < em; j++)
{

if (EM[j] == EM_trade[i])
{
if (O[j, NM[j]] == 0) { O[j, NM[j]] = Price_trade[i]; H[j, NM[j]] = Price_trade[i]; L[j, NM[j]] = Price_trade[i]; C[j, NM[j]] = Price_trade[i]; V[j,NM[j]]=Volume_trade[i];}

else { H[j, NM[j]] = Math.Max(H[j, NM[j]], Price_trade[i]); L[j, NM[j]] = Math.Min(L[j, NM[j]], Price_trade[i]); C[j, NM[j]] = Price_trade[i]; V[j,NM[j]]+=Volume_trade[i];}
}

}

}
s = 1; Thread.Sleep(100);
}
}


NMM++;
}

curHour = DateTime.Now.Hour;
curMin = DateTime.Now.Minute;
curDay = curHour * 100 + curMin;

 

if (curDay < 1843 && curDay > 1839)
{
for (j = 0; j < em; j++)
{

nach1 = 0;

for (i = 1; i < NM[j]; i++) { if (Time[j, i] < Time[j, i — 1]) nach1 = i; }

if (curDay < 1849) { if (Time[j, nach1] == 959) nach[j] = nach1 + 1; else nach[j] = nach1; }


Console.WriteLine("{0,6},{1,6},{2,6},{3,6},{4,6},{5,6},{6,6},{7,6}", EM[j], Time[j, NM[j]] * 100, O[j, NM[j]], H[j, NM[j]], L[j, NM[j]], C[j, NM[j]], Time[j, NM[j]] + 1, curDay);
// Вдогонку напишем информацию о состоянии канала

Console.WriteLine("\nSPOT IsConnected1: {0}, Data received: {1}\n", this.IsConnected, this.DataReceived);
}

Thread.Sleep(100);
}


}
}
// **********************************************************************
}


4. Меняем константу em на выбранное число эмитентов
5. Делаем файл Tiker_1.txt с нужными кодами эмитентов через запятую и кладем в нужную директорию. Меняем путь с D:\Day2\Tiker_1.txt на тот, который у Вас на компе.
6. Делаем консольное приложение в VS.
7. Настраиваем вывод по DDE из таблицы всех сделок (п. 1) как показано на следующем рисунке

Код для формирования минуток из таблицы всех сделок квика для спота

8. Запускаем консольное приложение.
Вот как выглядит это приложение на экране Вашего монитора

Код для формирования минуток из таблицы всех сделок квика для спота
Собственно все, теперь в приложении в массивах Time[j, i]; C[j, i] = 0; H[j, i]; L[j,i]; O[j, i]; V[j,i]; i от nach[j] до NM[j]-1 находятся время, Сlose, High, Low, Open и Volume текущих минуток для j-го эмитента без предторгового аукциона. В 18:43МСК в этих массивах будет полный набор внутридневных минуток без предторгового и послеторгового аукциона. Можно делать с ними, что нужно. И никаких купайлов, луа и стокшарпов.

P. S. Если «поиграть» с условиями по времени с учетом клирингов, то по аналогии можно и минутки с ФОРТСа делать.
★40
22 комментария
Главный вопрос. А зачем? Минутки в самом квике не кошерные?
kbrobot.ru, на графиках в онлайне — нет. Такое впечатление, что их строят по системному времени, а потом правят по таблице сделок.
avatar
На Lua это выглядит несколько проще.
avatar
 

local quantity = 100
local ind = «SiZ»

IsRun = false
begin = false

function main()

IsRun = true
r=false
begin = true

while begin do
n = getNumCandles(ind)--кол-во свечек, где ind = идентификатор графика
t, res, _ = getCandlesByIndex (ind, 0, n — quantity, quantity)--получить последние n свечей (для справки)
if res > 0 then
r=wind.Test(t)
begin = false
end
sleep(2000)
end

while IsRun do
sleep(2000)
end
end


А в проге в функции Test забираете из стека таблицу со свечками.
avatar
ну, биржевые котировки формируются на основе происходящих сделок. какого хрена брать эти сделки и делать самому работу, которая уже выполнена терминалом?
avatar
Nemo_2000, Если брать данные из таблицы всех сделок, а не с графика, то в квике получается быстрее. Такое впечетление, что в квике графики строятся с задержкой.
avatar
Очень сложно — на луа попроще было бы ..., да и не очень понятно — зачем самому лепить минутки, если терминал этим занимается )))
avatar
finstrateg, терминал может «слепить» минутку до ее окончания, а потом заменить «задним числом». На минутках, скачиваемых с графиков, я с этим сталкивался по 2-3 раза в день на Ри. В моей программе минутка появляется только после появления в таблице всех сделок, сделки из следующей минуты хотя бы по одному из выбранных эмитентов.
avatar
А. Г., да, интересно, как ведет себя в луа «приемник» данных — надо как-нибудь проверить, я котировки через CreateDataSource получаю, может оказаться актуальным для неликвида.
avatar
А. Г., в 6 версии квика таблица всех сделок для спота реализована?

Барсуков Андрей, сколько себя помню, она всегда там была. Другое дело, что знаю случаи, когда брокер подключал в квик только что-то одно либо фондовую секцию ММВБ, либо ФОРТС.
avatar
А. Г., спасибо, уточню у брокера, у меня строит только ФОРТС
А. Г.
>В моей программе минутка появляется только после появления в таблице всех сделок,
> сделки из следующей минуты хотя бы по одному из выбранных эмитентов.

На сколько я помню, этот кейс уже разбирался на форуме квика.
«Все сделки» тоже могут приходить не подряд. Это особенность рассылки информации биржей, так что смысла городить нет.
avatar
iQuik.ru, ну за два года работы этого скрипта такого в таблице всех сделок не было. Посмотрите в программе есть проверка этого.
avatar
А. Г., Вы уже неоднократно озвучивали причину по которой вынуждены были перейти на формирование минуток по таблице всех сделок, но если я правильно Вас понял, то случилось это тогда, когда еще не было CreateDataSource (если ошибаюсь — поправьте меня). В связи с чем вопрос: А не пробовали Вы сравнить «свои» минутки, с данными из CreateDataSource? Мне кажется, что там вероятность появления замеченной Вами проблемы должна быть значительно ниже (если не исключена вообще).
avatar
Prophetic, для того, чтобы качать минутки, мне пришлось:

— разобраться с DDE сервером Морошкина на С#;
— написать формирование таблиц минуток в QPILE с графиков.

 На изучение синтаксиса LUA меня уже не хватило, хотя бы потому, что мои системы уже перенесены из Excel в C#. И помимо изучения LUA, еще и разбираться в связках LUA->С# или LUA->MySQL… Нет, это выше моих сил. Поэтому про функционал LUA ничего сказать не могу. Мои претензии были  к функции GET_CANDLE из QPILE.
avatar
А. Г., Понял, спасибо.
Для информации (не уверен, что захотите этим заняться): На сегодняшний день необходимость использования DDE сервера у меня отпала. Нашел проект с открытым кодом QuikSharp, и тоже перевел всех роботов на C#. DDE сервер поднимать не нужно, Держать открытые таблицы в квике тоже не нужно.
avatar
Prophetic, в свое время, когда StockSharp был свободно распространяемым продуктом, я под него настроил квик по их инструкции. Даже на i7 в 8 гигами оперативки квик нормально работал только в приоритетном режиме, второй квик (а мне это надо, я торгую в нескольких квиках) тормозился «по черному». Поэтому я от связки квик+StockSharp отказался. А что за «зверь» QuikSharp — посмотрю.
avatar
А. Г., Я вынужден был перейти на C# тоже по причине жутких тормозов квика, когда в нем работало одновременно больше десятка роботов на Lua. Сейчас вся расчетная нагрузка вынесена за пределы терминала. В самом квике у меня запущена только вспомогательная прога на Lua, которая идет в комплекте с QuikSharp. Она запускается один раз и больше о ней уже не вспоминаешь. QuikSharp представляет из себя dll-ку, которая обеспечивает двухстороннюю связь с квиком (т.е. trans2quik тоже не нужен). через эту библиотеку можно принимать в свою программу любые market-data, доступные в самом квике, получать все колбеэки, и отправлять транзакции в квик. Это все, что нужно для создания практически любого робота. При этом, как я уже писал, нет никакой необходимости держать открытыми какие-либо таблицы в квике, но при желании можно получать данные непосредственно с открытых графиков (свечи, индикаторы).
avatar
О боже, сколько кода!!! Практически — поэзия в цифрах.
avatar
Я так понимаю, у квика клиента и сервера есть приоритеты — какие данные они передают сначала, а какие — потом. Сначала идут сделки, потом — стаканы, а потом только графики. И когда рынок резко дергается, загружается сразу много данных о сделках и изменения в стаканы, то графики могут притормознуть на несколько секунд, это очевидно и естественно, по-моему.
avatar
Если кому нужен квик или подобный другой терминал, можно взять на тестирование демку здесь: http://getanyplatform.com

теги блога А. Г.

....все тэги



UPDONW
Новый дизайн