VargoR написал: С дебилами из поддержки СБЕРА по этому вопросу спорить бесполезно. Эти придурки, чтобы убрать СМС подтверждения, мне в VDS предложили USB-токен вставить. В общем это не лечится. Я предполагаю, что они технически не могут отключить это, так как софт им допиливает сторонняя организация и своих программистов у них нет, а делать заявку и платить за переделку, они от жадности задушатся. Меняйте брокера на ВТБ или Альфу, но в Альфе гемор с электронной подписью, раз в квартал у меня она ломалась, а перезаказ новой от суток.
скажу больше, когда я согласился с предложением дебилов, оказалась, что функционал с USB-токенами не работает и вообще они отключают этот сервис
Мне надо сделать, чтобы папка Luaindicators для терминалов была задана принудительно(единая), чтобы терминал искал индикаторы в назначенной папке.
Другими словами, необходимо вынести папку LuaIndicators за пределы каталога установки терминала QUIK и настроить терминал так, чтобы он всегда обращался к этой конкретной папке при поиске индикаторов.
Версия 10.1.0.26 на Windows 7 Улучшил наглядность в скрипте, но результат такой же - нолики в ценах. Индикатор #test Идентификатор графику ставим 111 В папке рабочей папке QUIK появляется файл check1.txt
Код
Settings=
{
Name = '#test'
}
function writeToFile(filename, content)
local file_handle = io.open(filename, 'w')
if file_handle then
file_handle:write(content)
file_handle:close()
return true
else
return false
end
end
function Init()
return 1
end
function OnCalculate(index)
id_chart = '111'
local need_right_candles_count = 10
local line_number = 0
local candles_count = getNumCandles(id_chart)
local candles_from = candles_count - need_right_candles_count
local info = getDataSourceInfo()
check1 = tostring(id_chart)..'\n'..tostring(line_number)..'\n'..tostring(candles_from)..'\n'..tostring(need_right_candles_count)..'\n'..tostring(candles_count)..'\n'..tostring(info.class_code)..'\n'..tostring(info.sec_code)..'\n'
local result_table, result_candles_count, result_chart_name = getCandlesByIndex(id_chart, line_number, candles_from, need_right_candles_count)
if result_table == nil or #result_table == 0 then
return "Empty result_table"
end
local fieldNames = {}
for field, _ in pairs(result_table[1]) do
table.insert(fieldNames, field)
end
check1 = check1..'fieldNames:\n'..table.concat(fieldNames, '\n') .. '\n'
for i = #result_table, 1, -1 do
if result_table[i].datetime == nil or
result_table[i].datetime.day == nil or
result_table[i].datetime.month == nil or
result_table[i].datetime.year == nil or
result_table[i].datetime.hour == nil or
result_table[i].datetime.min == nil or
result_table[i].datetime.sec == nil then
return nil
end
local candle_datetime = string.format("%02d.%02d.%04d %02d:%02d:%02d",
result_table[i].datetime.day,
result_table[i].datetime.month,
result_table[i].datetime.year,
result_table[i].datetime.hour,
result_table[i].datetime.min,
result_table[i].datetime.sec)
local formattedFields = {
candle_datetime
}
for j, fieldName in ipairs(fieldNames) do
local fieldValue = result_table[i][fieldName]
table.insert(formattedFields, fieldName..'='..tostring(fieldValue))
end
check1 = check1 .. tostring(i)..'\t'..table.concat(formattedFields, '\t')..'\n'
end
local filename_w = getWorkingFolder()..'\\check1.txt'
if writeToFile(filename_w, check1) then
return
else
return "Failed to write to file"
end
end
Вначале перечислены исходные данные, затем список полей, который скрипт установил из списка, потом значения свечей. В первом поле идет расшифровка даты свечи из поля datetime
Перестал работать getCandlesByIndex причем время свечек видно в datetime, а остальные параметры open, high, low, close, volume и doesExist - нулевые. Написал код для тестирования, индикатор ставим на график с идентификатором SBER_Chart:
Код
Settings=
{
Name = '#test'
}
function writeToFile(filename, content)
local file_handle = io.open(filename, 'w')
if file_handle then
file_handle:write(content)
file_handle:close()
return true
else
return false
end
end
function Init()
return 1
end
function OnCalculate(index)
id_chart = 'SBER_Chart'
local need_right_candles_count = 10
local line_number = 0
local candles_count = getNumCandles(id_chart)
local candles_from = candles_count - need_right_candles_count
check1 = tostring(id_chart)..'\n'..tostring(line_number)..'\n'..tostring(candles_from)..'\n'..tostring(need_right_candles_count)..'\n'..tostring(candles_count)..'\n'
local result_table, result_candles_count, result_chart_name = getCandlesByIndex(id_chart, line_number, candles_from, need_right_candles_count)
if result_table == nil or #result_table == 0 then
return "Empty result_table"
end
local fieldNames = {}
for field, _ in pairs(result_table[1]) do
table.insert(fieldNames, field)
end
check1 = check1..'My_Time\t'..table.concat(fieldNames, '\t') .. '\n'
for i = #result_table, 1, -1 do
if result_table[i].datetime == nil or
result_table[i].datetime.day == nil or
result_table[i].datetime.month == nil or
result_table[i].datetime.year == nil or
result_table[i].datetime.hour == nil or
result_table[i].datetime.min == nil or
result_table[i].datetime.sec == nil then
return nil
end
local candle_datetime = string.format("%02d.%02d.%04d %02d:%02d:%02d",
result_table[i].datetime.day,
result_table[i].datetime.month,
result_table[i].datetime.year,
result_table[i].datetime.hour,
result_table[i].datetime.min,
result_table[i].datetime.sec)
local formattedFields = {
candle_datetime
}
for j, fieldName in ipairs(fieldNames) do
local fieldValue = result_table[i][fieldName]
table.insert(formattedFields, tostring(fieldValue))
end
check1 = check1 .. table.concat(formattedFields, '\t')..'\n'
end
local filename_w = getWorkingFolder()..'\\check1.txt'
if writeToFile(filename_w, check1) then
return
else
return "Failed to write to file"
end
end
На выходе получаем, нулевые данные (кроме времени свечей)
Просто откройте скриншот в первом сообщении, там внизу комментарий.
Думаю либо в формуле, что-то явно не хватает, либо Мосбиржа вносит кривые данные в статичную информацию об инструменте.
А баг с ноликом, который не нужен и опасен, у меня исправлен.
Код
function Get_gLast_Price_gr(zCLASSCODE,zSECCODE)
if zCLASSCODE==nil or zSECCODE==nil then return nil end
local Last_Price=getParamEx(zCLASSCODE,zSECCODE,'LAST').param_value
if Last_Price==0 then return nil end
return tostring_comma(Last_Price,nil,'.')
end
Однако есть проблема, что иногда код неправильно считает. т.е. Money2Lot выдаёт иногда 0, потому что Мосбиржа ставит большой LOTSIZE, но обычно правильно.
Наверно я что-то упустил в алгоритме. Подскажите где я ошибся.
Код
function Lot2Money(zCLASSCODE,zSECCODE,Lot)
local Price=tonumber(Get_gLast_Price_gr(zCLASSCODE,zSECCODE))
if Price==nil or Price==0 then return nil end
local LOTSIZE=getParamEx(zCLASSCODE,zSECCODE,"LOTSIZE").param_value
if LOTSIZE==nil then return nil end
message('Lot2Money'
..'\n'..'zCLASSCODE= '..tostring(zCLASSCODE)
..'\n'..'zSECCODE= '..tostring(zSECCODE)
..'\n'..'Lot= '..tostring(Lot)
..'\n'..'Price= '..tostring(Price)
..'\n'..'LOTSIZE= '..tostring(LOTSIZE)
..'\n'..'Lot*Price*LOTSIZE= '..tostring(Lot*Price*LOTSIZE)
)
return Lot*Price*LOTSIZE
end
Здесь я поставил заплатку, что не есть хорошо.
Код
function Money2Lot(zCLASSCODE, zSECCODE, Money)
if Money==nil then return 0 end
local Price=tonumber(Get_gLast_Price_gr(zCLASSCODE,zSECCODE))
if Price==nil or Price==0 then return nil end
local LOTSIZE=getParamEx(zCLASSCODE,zSECCODE,"LOTSIZE").param_value
if LOTSIZE==nil then return nil end
message('Money2Lot'
..'\n'..'zCLASSCODE= '..tostring(zCLASSCODE)
..'\n'..'zSECCODE= '..tostring(zSECCODE)
..'\n'..'Money= '..tostring(Money)
..'\n'..'Price= '..tostring(Price)
..'\n'..'LOTSIZE= '..tostring(LOTSIZE)
..'\n'..'Money/(Price * LOTSIZE= '..tostring(Money/(Price * LOTSIZE))
)
local RetLot=math.floor(Money/(Price * LOTSIZE))
if RetLot==0 then -- ЗАПЛАТКА: если брокер поставил избыточный LOTSIZE
RetLot=math.floor(Money/Price)
end
return RetLot
end
В стакане цен есть настройка, которая вызывается по Ctrl+E. Там можно поставить галочку "Нижняя панель". После этого внизу стакана будет видна панель лотов.
Вопрос: как мне получить программно эти цифры стакана цен.
Примечание: простое складывание объёмов в стакане (а там их всего 20 строк) всегда меньше цифр в Нижней панели)
Всё же хотелось бы получать информацию об открытых позициях из терминала. При этом не из табличек orders, trades, а из состояния счёта. Как минимум надо банально знать какие инструменты открыты, ведь orders и traders однодневные таблички, и после их зачищения робот с утра становится слепым.
Владимир написал: он знает в миллион раз лучще любого getPortfolioInfoEx
Я про это и говорю. Я тоже теперь считаю и храню данные за пределами QUIK. QUIK - это только для открытия ордеров, остальную же функциональность надо затачивать за пределами QUIK. Такое как хранение истории ордеров, расчет лотности, can_buy, плечо, информацию о портфеле: просто надо брать и смело переписывать getPortfolioInfoEx в свою фунцию.
Сейчас у меня констаны подгружаются в зависимости от того на каком компе (виртуальной машине) запущено. Т.е. каждой машинке своего брокера, со своими причудливыми брокерскими настройками в константах. Очень удобно в моём случае.
Код
local function get_Comp_Name()
os.execute('echo %computername% > C:\\Comp_Name.txt')
local file=io.open('C:\\Comp_Name.txt','r')
local Comp_Name=file:read("*all"):gsub("%s+","")
file:close()
message('[' .. Comp_Name .. ']')
file=io.open('C:\\Comp_Name.txt','w')
file:write(Comp_Name)
file:close()
return Comp_Name
end
local Tab=getPortfolioInfoEx (gFIRMID, gCLIENT_CODE, 2, gBOARD_TAG, gCURRENCY) -- https://luaq.ru/getPortfolioInfoEx.html
local Tab=getPortfolioInfoEx (gFIRMID, gCLIENT_CODE, 2) -- https://luaq.ru/getPortfolioInfoEx.html
local zPortfolio_value=Tab.portfolio_value -- Стоимость портфеля
local zCash_leverage=Tab.cash_leverage -- Плечо
local zProfit_loss=Tab.profit_loss -- Прибыль/Убытки
message('zPortfolio_value= '..tostring(zPortfolio_value)..'\nzCash_leverage= '..tostring(zCash_leverage)..'\nzProfit_loss= '..tostring(zProfit_loss))
Результат:
Код
zPortfolio_value= 45643.370000 -- это правильно
zCash_leverage= 0.000000
zProfit_loss= 0.000000
А при таком коде:
Код
local Tab=getPortfolioInfo (gFIRMID, gCLIENT_CODE) -- https://luaq.ru/getPortfolioInfo.html
local zLeverage=Tab.leverage -- Плечо
local zCur_leverage=Tab.cur_leverage -- Тек.плечо
message('zLeverage= '..tostring(zLeverage)..'\nzCur_leverage= '..tostring(zCur_leverage))
Результат:
Код
zLeverage= 101000.000000
zCur_leverage= 0.000000
Эта цифра котрую удалось выудить zLeverage принимае у разных брокеров такие значения,
Код
1501,00 -- это наверно надо делить на 100000
101000,00 -- это наверно надо делить на 100000
2,00 -- а это не надо делить, ибо похоже на правду
т.е. каждый кто-во что горазд Смысл этого абсурда примерно ясен: бороться с ветрянными мельницами себе дороже.Вывел плечо в константу gLVG. Я уже ржу над тем, что разработчики позиционируют QUIK как профессиональную систему, из профессионального там только ядро. Вот теперь моя коллекция констант для настройки счета. Сразу с их жесткого прописывайте и не тратьте впустую время.
Пытаюсь получить из таблицы "Клиентский портфель [SUR]" данные из графы << Плечо >> по строке Т2
Использую для этого код:
Код
local PortfolioInfoExTable=getPortfolioInfoEx (gFIRMID, gCLIENT_CODE, 2) -- https://luaq.ru/getPortfolioInfoEx.html
local zPortfolio_value=PortfolioInfoExTable.portfolio_value -- Стоимость портфеля
local zCash_leverage=PortfolioInfoExTable.cash_leverage -- Плечо
message(tostring(zPortfolio_value)..'\n\n'..tostring(zCash_leverage))
Но значение плеча zCash_leverage нулевое, хотя я вижу этот размер плеча явно в таблице "Клиентский портфель [SUR]" в строке Т2.
При этом мне успешно показывается стоимость портфеля - zPortfolio_value.
У меня такое ощущение, что в синтаксисе команды getPortfolioInfoEx должно быть ещё указание на валюту т.к. она указана в титуле окна.
На самом деле мне нужна графа <<Прибыль/Убытки>>, но для упрощения вопроса спрашиваю про графу <<Плечо>>.
Как мне получить размер Плеча или Прибыль/Убыток с начала дня по спотовому рынку?
В десктопном терминале QUIK на языке lua я даю команду buy_sell_info=getBuySellInfo('MC0002500000','404JNEF','TQBR','RUAL',0) -- https://luaq.ru/getBuySellInfo.html Мне возвращается таблица: table: 000000000A9B9750 Из таблицы я беру значение buy_sell_info.can_buy и оно равно nil (не определено) У других брокеров всё работает.
Техническая поддержка моего брокера порекомендовала брать данные о количестве доступных лотов для покупки из подтаблицы "Купить/Продать" таблицы "Клиентский портфель". Как обратиться к "Клиентскому портфелю" мне понятно portfolio = getPortfolioInfoEx ('MC0002500000','404JNEF', 2) и даже успешно оттуда вызывается плечо portfolio.leverage
Однако надо получить доступ именно к той таблице "Купить/Продать", котрая вызывается из таблицы "Клиентского портфеля" (а не из таблицы "Состояние счета") Как мне получить can_buy при для фондового рынка?
По причине того, что каждый брокер делает настройки, кто во что горазд, то код нерабочий. Наверно проще делать свой файл настроек для каждого брокера, где ручками прописывать три ключевых параметра торговли FIRMID, ACCOUNT, CLIENT_CODE
Код
function set_ACCOUNT_FIRMID_Spot()
if gACCOUNT == '' then
return gACCOUNT
end
if gSpot then
local TableName = 'trade_accounts'
local rows_total = getNumberOf(TableName)
for r = rows_total - 1, 0, -1 do
local table_row = getItem(TableName, r)
if tonumber(table_row.firmuse) == 1 and tonumber(table_row.trdacc_type) == 4 then
gFIRMID = table_row.firmid
gACCOUNT = table_row.trdaccid
if gCLIENT_CODE == '' then
local TableName2 = 'client_codes' --функция getNumberOf(«client_codes») возвращает количество доступных кодов клиента в терминале,
local rows_total2 = getNumberOf(TableName2)
for i = 0, rows_total2 - 1 do
local str_CLIENT_CODE = getItem(TableName2, i) --, а функция getItem(«client_codes», i) –строку, содержащую клиентский код с индексом i, где i может принимать значения от 0 до getNumberOf(«client_codes») -1
--Срок расчётов. Возможные значения:положительные целые числа, начиная с «0»,
--соответствующие срокам расчётовиз таблицы «Позиции по деньгам»: «0» –T0, «1» –T1, «2» –T2 и т.д.;
--отрицательные целые числа –технологические лимиты(используются для внутренней работы системы QUIK)
MoneyExTable = getMoneyEx(gFIRMID, str_CLIENT_CODE, 'EQTV', 'SUR', 2)
if MoneyExTable ~= nil then
if tonumber(MoneyExTable.currentbal) > 0 and tonumber(MoneyExTable.leverage) > 0 then
gCLIENT_CODE = str_CLIENT_CODE
end
end
end
if gCLIENT_CODE == '' then
gCLIENT_CODE = gACCOUNT
end
end
message(gCLIENT_CODE)
if gACCOUNT ~= '' then
return
end
end
end
return
end
end
Последнюю версию кода прилагаю, может у кого возникнет мысль как автоматизировать получение ключевых параметров для торговли.
function set_ACCOUNT_FIRMID()
if gACCOUNT~='' then return gACCOUNT end
if gSpot==true then
local TableName='trade_accounts' -- https://luaq.ru/getItem.html#param_table_26
local rows_total=getNumberOf(TableName);
for r=rows_total-1, 0, -1 do
local table_row=getItem(TableName,r);
if tonumber(table_row.firmuse)==1 and tonumber(table_row.trdacc_type)==4 then
gFIRMID=table_row.firmid
gACCOUNT=table_row.trdaccid
--if gCLIENT_CODE=='' then gCLIENT_CODE=gACCOUNT end
local TableName=getNumberOf('client_codes') --функция getNumberOf(«client_codes») возвращает количество доступных кодов клиента в терминале,
for i=rows_total-1, 0, -1 do
local string_row=getItem(TableName,i) -- а функция getItem(«client_codes», i) –строку, содержащую клиентский код с индексом i, где i может принимать значения от 0 до getNumberOf(«client_codes») -1
message(tostring(i)..'client_code1= '..tostring(string_row)) -- результат table: 000000001A1F2C10
message(tostring(i)..'client_code2= '..tostring(string_row[i])) -- результат nil
message(tostring(i)..'client_code3= '..tostring(string_row.client_code)) -- результат nil
end
stop();
if gACCOUNT~='' then return; end
end
end
stop();
end
Как понять, что за структура этой таблицы клиентов?
FIRMID и ACCOUNT для спотового рынка мне получить удалось из таблички фьючерсов
Код
function set_ACCOUNT_FIRMID()
if gACCOUNT~='' then return gACCOUNT end
if gSpot==true then
local TableName='trade_accounts' -- https://luaq.ru/getItem.html#param_table_26
local rows_total=getNumberOf(TableName);
for r=rows_total-1, 0, -1 do
local table_row=getItem(TableName,r);
if tonumber(table_row.firmuse)==1 and tonumber(table_row.trdacc_type)==4 then
gFIRMID=table_row.firmid
gACCOUNT=table_row.trdaccid
if gCLIENT_CODE=='' then gCLIENT_CODE=gACCOUNT end
if gACCOUNT~='' then return; end
end
end
stop();
end
end
Как получить CLIENT_CODE? В какой таблице он лежит?
Как определить доступна ли торговля по инструменту до открытия позиции., При отправке транзакции появляется ошибка брокера "Вам запрещена работа по данному инструменту".
При отправке транзакции появляется ошибка брокера "Вам запрещена работа по данному инструменту".
Как выяснилось брокер работает с ограниченным списком фьючерсных контрактов (и отправлят смотреть список доступных для торговли фьючерсов в эксель файл на своём сайте).
Однако котировки по всем фьючерсам брокер транслирует, но доступны для торговли только инструменты из их эксель-файла на сайте.
Потому при отправе транзакции появляется вышеназванная ошибка.
Какой командой мне определить, что инструмент доступен для торговли?
В окне "Фьючерсы FORTS Ввод заявки" есть кнопка [Max], которая позволяет автоматически подставить максимальное количество лотов в форму ручного ввода заявки.
По какой формуле идёт расчёт максимального количества лотов для фьючерсов в этом окне?
function CntTradesSellPosition(zCLASSCODE,zSECCODE)
cnt=0
local TableName='trades'
local rows_total = getNumberOf(TableName)
for r=rows_total-1, 0, -1 do
local table_row=getItem(TableName,r)
--message(tostring(table_row.flags));stop()
if table_row.class_code==zCLASSCODE and table_row.sec_code==zSECCODE and table_row.flags==36 then -- сделка продажа
cnt=cnt+1
end
end
return cnt
end
Пишу как самоучка, но мне как-то сложно (невозможно) вытаскивать из битовых флагов эти нужные значения, которые там закодированы в двоичной системе. В частности мне нужно определить только тип заявки ордера Buy или Sell.
Я так и не нашёл нигде пример алгоритма получения этих битовых значений, поэтому беру 10-тичные числа, но это кривовато, ибо по причине изменения других свойств и числа будут другие. Вот я методом научного тыка определил коды для продаж и второй флаг (бит) принимает разные значения: 64 = 1000000 36 = 100100 28 = 11100 1048604 = 100000000000000011100 - Продажа от стоплосса
Прошу, измените мой код, чтобы он нормально обрабатывал эти битовые флаги.
1.фьюченые инструменты постоянно меняются, но базовый актив - постоянный. 2.как я установил одному базовому активу может быть присвоено несколько фьючерсов по срокам истечения, например: BR = BRH3, BRG3, BRF3
Вопросы: 1.в какой таблице лежит список базовых активов? 2.какая таблица привязывает базовый актив к фьючерсам?
Хотелось бы получить Любой фьючерс по базовосу активу.