Sunday, 16 June 2013

How to call BTC-e API using LUA language


BTC-e.com is a web site where you can exchange virtual coins (like bitcoins, litecoins, etc), US dollars, euros and Russian rubles.

It provides a web interface for you to manually interact with.

Also if you are interested in building a bot to perform operations automatically, you could use their API.


In this article I am going to call the API from my Debian Sid system using Lua language.


Install Lua and dependencies


First I install lua 5.1 and luarocks to manage lua rocks.
$ sudo aptitude install lua5.1
$ sudo aptitude install luarocks

Once luarocks is already installed I install luasockets, and luasec. This will allow us to perform request using https protocol.
$ sudo luarocks install luasocket
$ sudo luarocks install luasec


INSTALL SHA2

http://code.google.com/p/sha2

Next we install sha2 rock to calculate hmac sha512 hashes.
$ sudo luarocks install sha2
$ cd /usr/local/lib/luarocks/rocks/sha2
$ sudo aptitude install lua-filesystem
$ sudo aptitude install lua5.1-md5-dev

Now we perform the tests:
$ lua test_sha2.lua
$ lua test_hmac.lua
They should pass OK.


INSTALL JSON

As the response will be coded using JSON we install lua-json.
$ sudo aptitude install lua-json


EXECUTING LUA CODE


Next step consists on creating a file e.g: test_API.lua, copying the following content in it and execute:

E.g: $ lua test_API.lua

#!/usr/bin/lua

BTC_api_key = "Put_Your_API_Key_Here"
BTC_api_secret = "Put_Your_API_Secret_Here"

nonce = 12  -- You need to increase this value needs by one every time you call the API.

-- Function to display table contents recursively
function show_table(t, spc)
   local spc = spc or ""
   spc = spc .. "  "

   print (spc .. "TABLE: ", t)
   for k,v in pairs(t) do
   if (type(v) ~= "table") then
   print (spc .. "EL: ", k, v)
   else
   show_table(v, spc)
   end
   end
   print (spc .. "End Table: ", t)
end

-- Function to encode strings in a suitable way for the web browser.
function url_encode(str)
  if (str) then
    str = string.gsub (str, "\n", "\r\n")
    --str = string.gsub (str, "([^%w ])",
    str = string.gsub (str, "([^%w _~%.%-])",
        function (c) return string.format ("%%%02X", string.byte(c)) end)
    str = string.gsub (str, " ", "+")
  end
  return str 
end


local function bintohex(s)
  return (s:gsub('(.)', function(c)
    return string.format('%02x', string.byte(c))
  end))
end 

local params = {}

--params["method"]="TransHistory"
--params["method"]="getInfo"
params.method="TradeHistory"
params["nonce"]=nonce
params["count"]=20
encoded_params = nil
for k,v in pairs(params) do
   print (k,v)
   if encoded_params then
   encoded_params = encoded_params .. "&" .. url_encode(k) .. "=" .. url_encode(v)
   else
   encoded_params = url_encode(k) .. "=" .. url_encode(v)
   end
end

print (encoded_params:format("Encoded params: %s"))


require "sha2"
require "hmac.sha2"

local sign = bintohex(hmac.sha512(encoded_params, BTC_api_secret))
print("sign: ", sign)


require("socket")
local https = require("ssl.https")

headers_table = {
   ["Content-type"] = "application/x-www-form-urlencoded",
   ["Key"] = BTC_api_key,
   ["Sign"] = sign
}

local url = "http://btc-e.com/tapi"
local body = encoded_params
headers_table["content-length"] = body:len()
local response = {}
local r, c, h = https.request{
  url= url,
  method = "POST",
  headers = headers_table,
  source = ltn12.source.string(body),
  sink = ltn12.sink.table(response)
}
print ("Status", r)

-- Show response as it is.
for k,v in pairs(response) do
   print (k,v)
end
print ("End of response")

-- Parse JSON
local json = require "json"
local tab = json.decode(response[1])
show_table(tab)


REFERENCE


http://stackoverflow.com/questions/10792898/equivalent-curl-for-lua-django-api-json-to-lua-json-post-method

http://code.google.com/p/sha2/

http://stackoverflow.com/questions/8286677/https-request-in-lua

http://w3.impa.br/~diego/software/luasocket/reference.html

http://json.luaforge.net


2 comentarios:

Anonymous said...

Thanks for this it made it easy to get started. BTW You will need to update the url_encode function to handle "_" if you want to use trading features.

Like this:

function url_encode(str)
if (str) then
str = string.gsub (str, "\n", "\r\n")
str = string.gsub (str, "([^%w %-%_%.%~])",
function (c) return string.format ("%%%02X", string.byte(c)) end)
str = string.gsub (str, " ", "+")
end
return str
end

Vicente Hernando said...

Hello,

many thanks for your patch!

I will update the post when I have some spare time.