Автор: Николай Камынин

Тот факт, что программа на  QPILE для  торгового терминала  QUIK должна быть представлена в текстовом виде, создает определенные проблемы для защиты авторских прав при ее распространении.

Для того, чтобы обеспечить некоторую защиту исходного текста программы применяют кодирование переменных таким образом, чтобы понять логику работы программы по ее тексту было затруднительно.

Программа, осуществляющая такое кодирование называется  ОБФУСКАТОР.

Предлагаю Вашему вниманию результат работы ОБФУСКАТОРА.

Фрагмент исходного текста программы:

‘ *****************************************************
FUNC detect_position()
table = «ORDERS»

max_index = GET_NUMBER_OF(table)
if(co_index > max_index + 1)
co_index = 1
end if

for orders_i from co_index to max_index
if( GET_VALUE(GET_ITEM(table,orders_i),»SECCODE») == SECCODE _
AND GET_VALUE(GET_ITEM(table,orders_i),»STATUS») == «FILLED» _
AND GET_VALUE(GET_ITEM(table,orders_i),»CLASSCODE») == CLASSCODE _
AND GET_VALUE(GET_ITEM(table,orders_i),»ACCOUNT») == ACCOUNT _
AND 0+GET_VALUE(GET_ITEM(table,orders_i),»NUMBER») > last_order_id )

save_needed = 1

last_order_id = 0+GET_VALUE(GET_ITEM(table,orders_i),»NUMBER»)

order_q = 0+GET_VALUE(GET_ITEM(table,orders_i),»QUANTITY»)
order_op = GET_VALUE(GET_ITEM(table,orders_i),»OPERATION»)
‘ ———————————————————————-
trade_q = 0
trade_p = 0
for trades_i from 1 to GET_NUMBER_OF(«TRADES»)
if(0+GET_VALUE(GET_ITEM(«TRADES»,trades_i),»ORDER_NUMBER») == last_order_id)
qq = 0+GET_VALUE(GET_ITEM(«TRADES»,trades_i),»QUANTITY»)
pp = 0+GET_VALUE(GET_ITEM(«TRADES»,trades_i),»PRICE»)

trade_q = trade_q + qq
trade_p = trade_p + (qq*pp)
end if
end for

if(trade_q > 0)
trade_p = trade_p / trade_q
end if
‘ ———————————————————————-
if(order_q != trade_q)
write_log(«Рассинхронизация заявок и сделок: » & last_order_id & «, » & order_q & «/» & trade_q)
last_order_id=last_order_id-1

RETURN
end if
‘ ———————————————————————-
log_action=»»
if( position == «n» )
set_position(order_op,trade_q,trade_p)
log_action=»Открытие позиции » & position & pquantity
else
if( (position == «L» AND order_op == «BUY») OR (position == «S» AND order_op == «SELL») )
log_action=»Наращивание позиции » & position & pquantity
pprice = pprice * pquantity + trade_p * trade_q
pquantity = pquantity + trade_q
pprice = pprice / pquantity
else
if(trade_q == pquantity)
log_action=»Закрытие позиции » & position & pquantity

position = «n»
pquantity = 0
else
if(trade_q < pquantity)
log_action=»Уменьшение позиции » & position & pquantity
pquantity = pquantity — order_q
else
log_action=»Переворот позиции » & position & pquantity
set_position(order_op,trade_q-pquantity,trade_p)
end if
end if
end if
end if

write_log(log_action & «: » & last_order_id & «, » & order_op & » » & order_q & «*» & FLOOR(trade_p*10)/10)

if(STOP_ORDER_MGR == 1)
check_stop_order()
end if
co_index = orders_i
‘ ———————————————————————-
end if
end for
END FUNC
‘ ***************************************************
‘ *                              MAIN PROGRAMM                               *
‘ ***************************************************
DELETE_ALL_ITEMS()
DELETE_ALL_LABELS(GRAPH_TAG)
‘ ***************************************************
get_qdata()
‘ проверим, все ли нужные данные считались из терминала
data_error=0
if(ltime == 0)
data_error = data_error + 1
end if
if(qcap == -1)
data_error = data_error + 2
end if
if(data_error > 0)
output=set_value(output,»A»,»Ожидание»)
add_item(outp_i,output)
output=set_value(output,»A»,»данных… [» & data_error & «]»)
add_item(outp_i,output)
RETURN
end if

if(qcap == 0)
output=set_value(output,»A»,»Ошибка»)
add_item(outp_i,output)
output=set_value(output,»A»,»определения»)
add_item(outp_i,output)
output=set_value(output,»A»,»рабочего»)
add_item(outp_i,output)
output=set_value(output,»A»,»капитала.»)
add_item(outp_i,output)
RETURN
end if
‘ ****************************************************
if(initialized == 0)
if(get_file_len(DATAFILE) == -1)
save_needed = 1
write_log(«Создание файла данных » & DATAFILE)
end if

initialized = 1
init_level_settings()
co_index = GET_NUMBER_OF(«ORDERS») + 1
write_log(«Инициализация: » & SECCODE & «.» & CLASSCODE & » » & co_index)
end if
‘ ***************************************************
if(save_needed == 0)
load_data()
else
save_data()
end if
‘ ***************************************************
detect_position()
get_bar(ldate,ltime)
‘ ***************************************************
if(position == «n»)
if(CALC1_SIZE>0)
exec_calc(CALC1_SIZE,PLOT_CALC1)
end if

if(CALC2_SIZE>0)
exec_calc(CALC2_SIZE,PLOT_CALC2)
end if

if(CALC_SATO>0)
exec_sato()
end if
else
position_calc()
end if
‘ ***************************************************
END_PROGRAM

Данный фрагмент после ОБФУСКАТОРА:

FUNC _17615()
_11352=»ORDERS»
_10735=GET_NUMBER_OF(_11352)
IF(_13740 > _10735+1)
_13740=1
END IF
FOR _15713 FROM _13740 TO _10735
IF(GET_VALUE(GET_ITEM(_11352,_15713),»_14815″)==_14815 AND GET_VALUE(GET_ITEM(_11352,_15713),»STATUS»)==»FILLED»AND GET_VALUE(GET_ITEM(_11352,_15713),»_19441″)==_19441 AND GET_VALUE(GET_ITEM(_11352,_15713),»_12233″)==_12233 AND 0+GET_VALUE(GET_ITEM(_11352,_15713),»NUMBER»)> _11644)
_12176=1
_11644=0+GET_VALUE(GET_ITEM(_11352,_15713),»NUMBER»)
_15951=0+GET_VALUE(GET_ITEM(_11352,_15713),»_18947″)
_15433=GET_VALUE(GET_ITEM(_11352,_15713),»OPERATION»)
_10311=0
_19544=0
FOR _16652 FROM 1 TO GET_NUMBER_OF(«TRADES»)
IF(0+GET_VALUE(GET_ITEM(«TRADES»,_16652),»ORDER_NUMBER»)==_11644)
_19097=0+GET_VALUE(GET_ITEM(«TRADES»,_16652),»_18947″)
_16416=0+GET_VALUE(GET_ITEM(«TRADES»,_16652),»PRICE»)
_10311=_10311+_19097
_19544=_19544+(_19097*_16416)
END IF
END FOR
IF(_10311 > 0)
_19544=_19544/_10311
END IF
IF(_15951 !=_10311)
_12896(«РАССИНХРОНИЗАЦИЯ ЗАЯВОК И СДЕЛОК:»&_11644&»,»&_15951&»/»&_10311)
_11644=_11644-1
RETURN
END IF
_11294=»»
IF(_13275==»N»)
_15519(_15433,_10311,_19544)
_11294=»ОТКРЫТИЕ ПОЗИЦИИ»&_13275&_18661
ELSE
IF((_13275==»L»AND _15433==»BUY»)OR(_13275==»S»AND _15433==»SELL»))
_11294=»НАРАЩИВАНИЕ ПОЗИЦИИ»&_13275&_18661
_13346=_13346*_18661+_19544*_10311
_18661=_18661+_10311
_13346=_13346/_18661
ELSE
IF(_10311==_18661)
_11294=»ЗАКРЫТИЕ ПОЗИЦИИ»&_13275&_18661
_13275=»N»
_18661=0
ELSE
IF(_10311 < _18661)
_11294=»УМЕНЬШЕНИЕ ПОЗИЦИИ»&_13275&_18661
_18661=_18661-_15951
ELSE
_11294=»ПЕРЕВОРОТ ПОЗИЦИИ»&_13275&_18661
_15519(_15433,_10311-_18661,_19544)
END IF
END IF
END IF
END IF
_12896(_11294&»:»&_11644&»,»&_15433&» «&_15951&»*»&FLOOR(_19544*10)/10)
IF(_10340==1)
_18034()
END IF
_13740=_15713
END IF
END FOR
END FUNC
DELETE_ALL_ITEMS()
DELETE_ALL_LABELS(_16060)
_10208()
_16373=0
IF(_15520==0)
_16373=_16373+1
END IF
IF(_19072==-1)
_16373=_16373+2
END IF
IF(_16373 > 0)
_14560=SET_VALUE(_14560,»A»,»ОЖИДАНИЕ»)
ADD_ITEM(_17645,_14560)
_14560=SET_VALUE(_14560,»A»,»ДАННЫХ… [«&_16373&»]»)
ADD_ITEM(_17645,_14560)
RETURN
END IF
IF(_19072==0)
_14560=SET_VALUE(_14560,»A»,»ОШИБКА»)
ADD_ITEM(_17645,_14560)
_14560=SET_VALUE(_14560,»A»,»ОПРЕДЕЛЕНИЯ»)
ADD_ITEM(_17645,_14560)
_14560=SET_VALUE(_14560,»A»,»РАБОЧЕГО»)
ADD_ITEM(_17645,_14560)
_14560=SET_VALUE(_14560,»A»,»КАПИТАЛА.»)
ADD_ITEM(_17645,_14560)
RETURN
END IF
IF(_10180==0)
IF(GET_FILE_LEN(_10529)==-1)
_12176=1
_12896(«СОЗДАНИЕ ФАЙЛА ДАННЫХ»&_10529)
END IF
_10180=1
_14006()
_13740=GET_NUMBER_OF(«ORDERS»)+1
_12896(«ИНИЦИАЛИЗАЦИЯ:»&_14815&».»&_19441&» «&_13740)
END IF
IF(_12176==0)
_17674()
ELSE
_17331()
END IF
_17615()
_10206(_19835,_15520)
IF(_13275==»N»)
IF(_10864>0)
_14614(_10864,_10146)
END IF
IF(_15337>0)
_14614(_15337,_13504)
END IF
IF(_17235>0)
_15263()
END IF
ELSE
_12332()
END IF
END_PROGRAM

Кроме того, данная программа  выполняет сборку  портфеля

на основе основной программы и библиотек функций, оптимизирует текст программы,

включая в него из библиотек лишь используемые функции,

убирает комментарии и выявляет обращение к функциям,

описание которых отсутствует в библиотеках.

Программа распространяется на коммерческой основе.

Tags: , ,

Написал препроцессор для обработки исходников QPILE,

который выполняет функции сборки портфеля

на основе основной программы и библиотек функций.
Кроме того, он оптимизирует код программы,

включая в него из библиотек лишь используемые функции,

убирает комментарии и выявляет обращение к функциям,

описание которых отсутствует в библиотеках.
В планах развития данного пакета — включение функций обфускатора, макросов.
Хотелось бы услышать мнения по востребованности

и пожелания по развитию данного продукта.

С целью изучения спроса на данный продукт,

принимаются предварительные заявки.

По просьбе читателей привожу текст программы , реализующей фильтр АМА Кауфмана на языке программирования  QPILE для торгового терминала QUIK

Несколько замечаний к программе.

Программа рисует график в реальном времени.

Перерисовка исторических данных не предусмотрена.

Программа вычисляет значение и отображает его на график с идентификатором равным коду инструмента, в данном примере это  SBER03 — обычная акция сбербанка.

PORTFOLIO_EX NK_AMA;
DESCRIPTION автор:  НИКОЛАЙ КАМЫНИН  16.04.2011
фильтр АМА Кауфмана;
CLIENTS_LIST ALL_CLIENTS;
FIRMS_LIST ALL_FIRMID;
PROGRAM
SECCODE=»SBER03″
New_Global(«INIT»,0)
IF INIT=0
New_Global(«FH»,24)
New_Global(«P»,10)
New_Global(«AMA»,0)
New_Global(«NOISE»,0)
New_Global(«CP»,0)
New_Global(«D_OLD»,-1)
New_Global(«T_OLD»,-1)
New_Global(«Fastest»,0.6667)
New_Global(«Slowest»,0.0645)
ERR=DELETE_ALL_LABELS(SECCODE)
CLASSCODE=GET_VALUE (GET_SECURITY_INFO («»,SECCODE), «CLASS_CODE»)
INIT=1
END IF
‘~~~~~~~~~~~~~~~~~
FUNC C(k)
Lcol=GET_COLLECTION_COUNT (CP)
IF k>Lcol
k=Lcol
END IF
result=GET_COLLECTION_ITEM(CP,k)
END FUNC
‘~~~~~~~~~~~
D= GET_INFO_PARAM («TRADEDATE»)
DATE=SUBSTR (D,6,4) & SUBSTR (D,3,2) & SUBSTR (D,0,2)
TIME=GET_PARAM (CLASSCODE,SECCODE,»TIME»)
IF DATE-D_OLD!=0 OR TIME-T_OLD!=0
x=GET_PARAM (CLASSCODE,SECCODE,»last»)
CP=INSERT_COLLECTION_ITEM(CP,0,x)

‘~~~~~~вычисление нового значения фильтра~~~~~~~~

SIGNAL = ABS(C(0)-C(P))
NOISE=NOISE+ABS(C(0)-C(1))-ABS(C(P+1)-C(P))
ER=0
If Noise > 0
ER = SIGNAL/NOISE
END IF
Smooth = ER*(Fastest- Slowest) + Slowest
AMA = AMA + Smooth *
Smooth * (C(0)-AMA)

»~~~~~~~~~конец вычислений нового значения ~~~~~~~~~

st=SET_VALUE(«»,»AMA»,AMA)
ADD_ITEM (0, st)
‘~~~~~~~~~~~~
M_AMA=SET_VALUE(SET_VALUE(«»,»DATE»,DATE),»TIME»,TIME)
M_AMA=SET_VALUE(AMA,»YVALUE»,AMA)

M_AMA=SET_VALUE(SET_VALUE(SET_VALUE(M_AMA,»B»,255),»G»,255),»R»,0)
M_AMA=SET_VALUE(SET_VALUE(M_AMA,»TEXT»,»-«),»FONT_HEIGHT»,FH)

id=ADD_LABEL (SECCODE,M_AMA)
D_OLD=DATE
T_OLD=TIME
END IF
END_PROGRAM
PARAMETER AMA;
PARAMETER_TITLE AMA;
PARAMETER_DESCRIPTION AMA;
PARAMETER_TYPE STRING(10);
END