|
|
|
|
@ -1,143 +1,17 @@
@@ -1,143 +1,17 @@
|
|
|
|
|
local alien = require("alien") |
|
|
|
|
-- QUIK Ticker Information System |
|
|
|
|
|
|
|
|
|
json = require "JSON" |
|
|
|
|
date = require "date" |
|
|
|
|
require "string" |
|
|
|
|
struct = require "alien.struct" |
|
|
|
|
|
|
|
|
|
w32sleep = alien.kernel32.Sleep |
|
|
|
|
w32sleep:types { ret = "void", abi = "stdcall", "int" } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
zmq_pollitem = alien.defstruct { |
|
|
|
|
{"socket", "pointer"}, |
|
|
|
|
{"fd", "int"}, |
|
|
|
|
{"events", "short"}, |
|
|
|
|
{"revents", "short"} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
zmq_ctx_new = alien.libzmq.zmq_ctx_new |
|
|
|
|
zmq_ctx_new:types { ret = "pointer", abi="stdcall" } |
|
|
|
|
|
|
|
|
|
zmq_ctx_term = alien.libzmq.zmq_ctx_term |
|
|
|
|
zmq_ctx_term:types { ret = "int", abi="stdcall", "pointer" } |
|
|
|
|
|
|
|
|
|
zmq_bind = alien.libzmq.zmq_bind |
|
|
|
|
zmq_bind:types { ret = "int", abi="stdcall", "pointer", "string" } |
|
|
|
|
|
|
|
|
|
zmq_close = alien.libzmq.zmq_close |
|
|
|
|
zmq_close:types { ret = "int", abi="stdcall", "pointer" } |
|
|
|
|
|
|
|
|
|
zmq_disconnect = alien.libzmq.zmq_disconnect |
|
|
|
|
zmq_disconnect:types { ret = "int", abi="stdcall", "pointer", "string" } |
|
|
|
|
|
|
|
|
|
zmq_setsockopt = alien.libzmq.zmq_setsockopt |
|
|
|
|
zmq_setsockopt:types { ret = "int", abi="stdcall", "pointer", "int", "pointer", "int" } |
|
|
|
|
|
|
|
|
|
zmq_getsockopt = alien.libzmq.zmq_setsockopt |
|
|
|
|
zmq_getsockopt:types { ret = "int", abi="stdcall", "pointer", "int", "pointer", "int" } |
|
|
|
|
|
|
|
|
|
zmq_errno = alien.libzmq.zmq_errno |
|
|
|
|
zmq_errno:types { ret = "int", abi="stdcall" } |
|
|
|
|
|
|
|
|
|
zmq_msg_close = alien.libzmq.zmq_msg_close |
|
|
|
|
zmq_msg_close:types { ret = "int", abi="stdcall", "pointer" } |
|
|
|
|
|
|
|
|
|
zmq_msg_data = alien.libzmq.zmq_msg_data |
|
|
|
|
zmq_msg_data:types { ret = "pointer", abi="stdcall", "pointer" } |
|
|
|
|
|
|
|
|
|
zmq_msg_get = alien.libzmq.zmq_msg_get |
|
|
|
|
zmq_msg_get:types { ret = "int", abi="stdcall", "pointer", "int" } |
|
|
|
|
|
|
|
|
|
zmq_msg_init_size = alien.libzmq.zmq_msg_init_size |
|
|
|
|
zmq_msg_init_size:types { ret = "int", abi="stdcall", "pointer", "int" } |
|
|
|
|
|
|
|
|
|
zmq_msg_init = alien.libzmq.zmq_msg_init |
|
|
|
|
zmq_msg_init:types { ret = "int", abi="stdcall", "pointer" } |
|
|
|
|
|
|
|
|
|
zmq_msg_more = alien.libzmq.zmq_msg_more |
|
|
|
|
zmq_msg_more:types { ret = "int", abi="stdcall", "pointer" } |
|
|
|
|
|
|
|
|
|
zmq_msg_recv = alien.libzmq.zmq_msg_recv |
|
|
|
|
zmq_msg_recv:types { ret = "int", abi="stdcall", "pointer", "pointer", "int" } |
|
|
|
|
|
|
|
|
|
zmq_msg_send = alien.libzmq.zmq_msg_send |
|
|
|
|
zmq_msg_send:types { ret = "int", abi="stdcall", "pointer", "pointer", "int" } |
|
|
|
|
|
|
|
|
|
zmq_msg_set = alien.libzmq.zmq_msg_set |
|
|
|
|
zmq_msg_set:types { ret = "int", abi="stdcall", "pointer", "int", "int" } |
|
|
|
|
|
|
|
|
|
zmq_msg_size = alien.libzmq.zmq_msg_size |
|
|
|
|
zmq_msg_size:types { ret = "int", abi="stdcall", "pointer" } |
|
|
|
|
|
|
|
|
|
zmq_poll = alien.libzmq.zmq_poll |
|
|
|
|
zmq_poll:types { ret = "int", abi="stdcall", "pointer", "int", "int" } |
|
|
|
|
|
|
|
|
|
zmq_recv = alien.libzmq.zmq_recv |
|
|
|
|
zmq_recv:types { ret = "int", abi="stdcall", "pointer", "pointer", "int", "int"} |
|
|
|
|
|
|
|
|
|
zmq_send = alien.libzmq.zmq_send |
|
|
|
|
zmq_send:types { ret = "int", abi="stdcall", "pointer", "pointer", "int", "int"} |
|
|
|
|
|
|
|
|
|
zmq_socket = alien.libzmq.zmq_socket |
|
|
|
|
zmq_socket:types { ret = "pointer", abi="stdcall", "pointer", "int"} |
|
|
|
|
|
|
|
|
|
zmq_version = alien.libzmq.zmq_version |
|
|
|
|
zmq_version:types { ret = "void", abi="stdcall", "ref int", "ref int", "ref int"} |
|
|
|
|
|
|
|
|
|
zmq_unbind = alien.libzmq.zmq_unbind |
|
|
|
|
zmq_unbind:types { ret = "int", abi="stdcall", "pointer", "string"} |
|
|
|
|
|
|
|
|
|
function zmq_msg_new() |
|
|
|
|
local buf = alien.buffer(64) |
|
|
|
|
return buf |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
function zmq_msg_as_string(msg) |
|
|
|
|
return alien.tostring(zmq_msg_data(msg), zmq_msg_size(msg)) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
ZMQ_PAIR = 0 |
|
|
|
|
ZMQ_PUB = 1 |
|
|
|
|
ZMQ_SUB = 2 |
|
|
|
|
ZMQ_REQ = 3 |
|
|
|
|
ZMQ_REP = 4 |
|
|
|
|
ZMQ_DEALER = 5 |
|
|
|
|
ZMQ_ROUTER = 6 |
|
|
|
|
ZMQ_PULL = 7 |
|
|
|
|
ZMQ_PUSH = 8 |
|
|
|
|
ZMQ_XPUB = 9 |
|
|
|
|
ZMQ_XSUB = 10 |
|
|
|
|
ZMQ_STREAM = 11 |
|
|
|
|
|
|
|
|
|
ZMQ_POLLIN = 1 |
|
|
|
|
ZMQ_POLLOUT = 2 |
|
|
|
|
ZMQ_POLLERR = 4 |
|
|
|
|
|
|
|
|
|
ZMQ_SNDMORE = 2 |
|
|
|
|
ZMQ_LINGER = 17 |
|
|
|
|
local zmq = require "zeromq" |
|
|
|
|
local quik = require "quik_api" |
|
|
|
|
|
|
|
|
|
running = true |
|
|
|
|
|
|
|
|
|
function zmq_msg_from_string(str) |
|
|
|
|
local msg = zmq_msg_new() |
|
|
|
|
zmq_msg_init_size(msg, str:len()) |
|
|
|
|
buf = zmq_msg_data(msg) |
|
|
|
|
bsource = alien.buffer(str) |
|
|
|
|
alien.memcpy(buf, bsource, str:len()) |
|
|
|
|
return msg |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
function zmq_msg_empty() |
|
|
|
|
local msg = zmq_msg_new() |
|
|
|
|
zmq_msg_init(msg) |
|
|
|
|
return msg |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
function get_data(class, code) |
|
|
|
|
local lot_size = tonumber(getParamEx(class, code, "LOTSIZE").param_value) |
|
|
|
|
local tick_size = tonumber(getParamEx(class, code, "SEC_PRICE_STEP").param_value) |
|
|
|
|
local tick_value = tonumber(getParamEx(class, code, "STEPPRICET").param_value) |
|
|
|
|
local long_name = getParamEx(class, code, "LONGNAME").param_image |
|
|
|
|
local lot_size = tonumber(quik.getParamEx(class, code, "LOTSIZE").param_value) |
|
|
|
|
local tick_size = tonumber(quik.getParamEx(class, code, "SEC_PRICE_STEP").param_value) |
|
|
|
|
local tick_value = tonumber(quik.getParamEx(class, code, "STEPPRICET").param_value) |
|
|
|
|
local long_name = quik.getParamEx(class, code, "LONGNAME").param_image |
|
|
|
|
|
|
|
|
|
return { ticker = class .. "#" .. code, |
|
|
|
|
lot_size = lot_size, |
|
|
|
|
@ -147,76 +21,66 @@ function get_data(class, code)
@@ -147,76 +21,66 @@ function get_data(class, code)
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
function handle_message(msg) |
|
|
|
|
message("Incoming message") |
|
|
|
|
local rq = json:decode(zmq_msg_as_string(msg)) |
|
|
|
|
quik.message("Incoming message") |
|
|
|
|
local rq = json:decode(msg) |
|
|
|
|
local class, code = string.match(rq.ticker, "(%w+)#(%w+)") |
|
|
|
|
message("Requested: " .. rq.ticker) |
|
|
|
|
quik.message("Requested: " .. rq.ticker) |
|
|
|
|
|
|
|
|
|
local data = get_data(class, code) |
|
|
|
|
if data == nil then |
|
|
|
|
message("Error") |
|
|
|
|
return zmq_msg_from_string("ERROR: can't get data: (" .. class .. "/" .. code .. ")" ), zmq_msg_empty() |
|
|
|
|
quik.message("Error") |
|
|
|
|
return "ERROR: can't get data: (" .. class .. "/" .. code .. ")", "" |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
message("Returning data") |
|
|
|
|
return zmq_msg_from_string("OK"), zmq_msg_from_string(json:encode(data)) |
|
|
|
|
quik.message("Returning data") |
|
|
|
|
return "OK", json:encode(data) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
ctx = nil |
|
|
|
|
sock = nil |
|
|
|
|
Ctx = nil |
|
|
|
|
Sock = nil |
|
|
|
|
|
|
|
|
|
function OnStop() |
|
|
|
|
if sock then |
|
|
|
|
zmq_close(sock) |
|
|
|
|
sock = nil |
|
|
|
|
if Sock then |
|
|
|
|
Sock:close() |
|
|
|
|
Sock = nil |
|
|
|
|
end |
|
|
|
|
if ctx then |
|
|
|
|
zmq_ctx_term(ctx) |
|
|
|
|
ctx = nil |
|
|
|
|
if Ctx then |
|
|
|
|
Ctx:term() |
|
|
|
|
Ctx = nil |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
function main() |
|
|
|
|
local status, err = pcall(pmain) |
|
|
|
|
if not status then |
|
|
|
|
message("Error: " .. err) |
|
|
|
|
quik.message("Error: " .. err) |
|
|
|
|
end |
|
|
|
|
OnStop() |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
function pmain() |
|
|
|
|
ctx = zmq_ctx_new() |
|
|
|
|
sock = zmq_socket(ctx, ZMQ_REP) |
|
|
|
|
local linger = alien.array("int", {0}) |
|
|
|
|
zmq_setsockopt(sock, ZMQ_LINGER, linger.buffer, 4) |
|
|
|
|
local rc = zmq_bind(sock, "tcp://*:5523") |
|
|
|
|
if rc ~= 0 then |
|
|
|
|
message("Bind error: " .. tostring(rc)) |
|
|
|
|
local err |
|
|
|
|
Ctx = zmq.new_ctx() |
|
|
|
|
Sock = Ctx:socket(zmq.REP) |
|
|
|
|
Sock:setsockopt_int(zmq.SOCKOPT_LINGER, 0) |
|
|
|
|
_, err = Sock:bind("tcp://*:5523") |
|
|
|
|
if err then |
|
|
|
|
quik.message("Bind error: " .. tostring(rc)) |
|
|
|
|
return |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
local poller = Ctx:poller() |
|
|
|
|
poller:add(Sock, zmq.POLLIN) |
|
|
|
|
while running do |
|
|
|
|
local pi = zmq_pollitem:new() |
|
|
|
|
pi.socket = sock |
|
|
|
|
pi.fd = 0 |
|
|
|
|
pi.events = ZMQ_POLLIN |
|
|
|
|
pi.revents = 0 |
|
|
|
|
|
|
|
|
|
rc = zmq_poll(pi(), 1, 60000) |
|
|
|
|
if rc > 0 and pi.revents == ZMQ_POLLIN then |
|
|
|
|
message("Incoming") |
|
|
|
|
local msg = zmq_msg_new() |
|
|
|
|
zmq_msg_init(msg) |
|
|
|
|
rc = zmq_msg_recv(msg, sock, 0) |
|
|
|
|
if rc == -1 then |
|
|
|
|
running = false |
|
|
|
|
message("rc: " .. tostring(rc) .. "; " .. tostring(zmq_errno())) |
|
|
|
|
else |
|
|
|
|
local events, msg |
|
|
|
|
events, err = poller:poll(60000) |
|
|
|
|
if #events > 0 then |
|
|
|
|
quik.message("Incoming") |
|
|
|
|
msg, err = Sock:recv() |
|
|
|
|
if not err then |
|
|
|
|
local outmsg_header, outmsg_data = handle_message(msg) |
|
|
|
|
zmq_msg_send(outmsg_header, sock, ZMQ_SNDMORE) |
|
|
|
|
zmq_msg_send(outmsg_data, sock, 0) |
|
|
|
|
Sock:send({outmsg_header, outmsg_data}) |
|
|
|
|
end |
|
|
|
|
zmq_msg_close(msg) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|