-
Apr 18th, 2015, 11:21 AM
#1
[RESOLVED] Help communicating with web API (bitfinex)
Hello guys, I am trying to communicate with a web API I found a VB.NET example but it encodes to Base64 and UTF8 and communicates via JSON (POST/GET)
here is the link post #5
I'm not sure how I could communicate with the API from vb6.
I know I will need to encode to Base64 and then make a request fill the header and send the request using POST then wait for the reply (in a loop?) using GET?
This is how to do it in VB.Net..
Code:
Sub GetBalance()
Dim nonce As Long = CLng(DateTime.UtcNow.Subtract(New DateTime(1970, 1, 1)).TotalSeconds)
'returns a strictly increasing timestamp based number e.g. 1402207693893
Dim path As String = "https://api.bitfinex.com/v1/balances"
Dim paramDict As String = "{""request"": ""/v1/balances"",""nonce"": """ & nonce & """}"
'ie. {"request": "/v1/balances","nonce": "1402207693893"}
Dim payload As String = Convert.ToBase64String(Encoding.UTF8.GetBytes(paramDict))
'API Sign
Dim hmac As New HMACSHA384(Encoding.UTF8.GetBytes("SECRET KEY GOES HERE"))
'My API SECRET
Dim hash As Byte() = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload))
Dim hexHash As String = BitConverter.ToString(hash).Replace("-", "").ToLower()
Dim headers As New NameValueCollection()
headers.Add("X-BFX-APIKEY", "KEY GOES HERE")
'My API KEY
headers.Add("X-BFX-PAYLOAD", payload)
headers.Add("X-BFX-SIGNATURE", hexHash)
'POST data
Try
'create post request
Dim request As HttpWebRequest = DirectCast(HttpWebRequest.Create(path), HttpWebRequest)
request.KeepAlive = True
request.Method = "POST"
'add headers
request.Headers.Add(headers)
'write out payload
Dim byteArray As Byte() = System.Text.Encoding.UTF8.GetBytes(paramDict)
request.ContentLength = byteArray.Length
Using writer = request.GetRequestStream()
writer.Write(byteArray, 0, byteArray.Length)
End Using
'read reply
Using response = TryCast(request.GetResponse(), System.Net.HttpWebResponse)
Using reader = New System.IO.StreamReader(response.GetResponseStream())
'get reply (JSON)
Dim responseContent As String = reader.ReadToEnd()
MsgBox(responseContent)
End Using
End Using
Catch e As Exception
'always throws an exception here
Debug.WriteLine(e.Message)
End Try
End Sub
Edit:
I need help mostly with this part
Code:
Dim payload As String = Convert.ToBase64String(Encoding.UTF8.GetBytes(paramDict))
'API Sign
Dim hmac As New HMACSHA384(Encoding.UTF8.GetBytes("SECRET KEY GOES HERE"))
'My API SECRET
Dim hash As Byte() = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload))
Dim hexHash As String = BitConverter.ToString(hash).Replace("-", "").ToLower()
(Python Example if it helps)
Another quick question is if it matters if I use inet or winsock or xmlhttp to send the header? As long as the information inside is correct it should work right?
Last edited by Max187Boucher; Apr 18th, 2015 at 10:37 PM.
-
Apr 18th, 2015, 12:40 PM
#2
Re: Help communicating with web API
This is what I got so far looking for base64 function and not 100% sure what this 'HMACSHA384(Encoding.UTF8.GetBytes)' function is? does it simply encode to sha384? not sure what it is doing
Code:
Private Sub Command2_Click()
Dim nonce As Long
Dim path As String
Dim sRequest As String
Dim paramDict As String:
Dim payload As String:
'Dim hmac As New HMACSHA384(Encoding.UTF8.GetBytes("SECRET KEY GOES HERE")) '***** Not sure *******
Dim hash As Byte
Dim hexHash As String
Dim header As New Collection
nonce = CLng(Time) 'returns a strictly increasing timestamp based number e.g. 1402207693893
path = "https://api.bitfinex.com/v1/balances"
sRequest = "/v1/balances"
paramDict = "{" & """request""" & ": " & sRequest & "," & """nonce""" & ": " & """ & nonce & """ & "}"
payload = EncodeToBase64(paramDict) '******* Need Base64 Function ********
hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload)) '**** Not Sure *****
hash = BitConverter.ToString(hash).Replace("-", "").ToLower() 'convert bytes to string replace any "-" and LCase() the string then back to byte?
header.Add """X-BFX-APIKEY""" & ": " & APIKEY
header.Add """X-BFX-PAYLOAD""" & ": " & payload
header.Add """X-BFX-SIGNATURE""" & ": " & hexHash
Inet1.OpenURL path, header
End Sub
-
Apr 18th, 2015, 07:12 PM
#3
Re: Help communicating with web API
Here's a VB6-class-encapsulation which covers the above,
(it has dependencies to vbRichClient5 and WinHttp 5.1):
Edit: Note, that the RichClient-version has to be at least 5.0.26 (the SHA384 and SHA512 methods were new additions to cCrypt)
Code:
Option Explicit
Const BitFinexApiVersion$ = "/v1", BitFinexApiURL = "https://api.bitfinex.com" & BitFinexApiVersion
Private mBitFinexKey As String, mBitFinexSecret As String, mCrypt As cCrypt
Friend Sub Init(BitFinexKey As String, BitFinexSecret As String)
mBitFinexKey = BitFinexKey
mBitFinexSecret = BitFinexSecret
Set mCrypt = New_c.Crypt
End Sub
Public Function DoAuthenticatedRPC(RequestSuffix As String, Result As cCollection, Optional httpStatusText As String, Optional ByVal PayLoad As cCollection) As Boolean
Dim sPayload_UTF8_Base64 As String, http As New WinHttpRequest
If PayLoad Is Nothing Then Set PayLoad = New_c.JSONObject
PayLoad.Prop("request") = BitFinexApiVersion & RequestSuffix
PayLoad.Prop("nonce") = CStr(New_c.Connection.UniqueID64) 'that's a time-based, increasing int64-value
sPayload_UTF8_Base64 = mCrypt.Base64Enc(PayLoad.SerializeToJSONUTF8)
http.Open "POST", BitFinexApiURL & RequestSuffix, False
http.SetRequestHeader "X-BFX-APIKEY", mBitFinexKey
http.SetRequestHeader "X-BFX-PAYLOAD", sPayload_UTF8_Base64
http.SetRequestHeader "X-BFX-SIGNATURE", mCrypt.HMAC_SHA384(sPayload_UTF8_Base64, mCrypt.VBStringToUTF8(mBitFinexSecret))
http.Send
httpStatusText = http.Status & ": " & http.StatusText
If http.Status <> 200 Then Exit Function
Set Result = New_c.JSONDecodeToCollectionUTF8(http.ResponseBody)
DoAuthenticatedRPC = True
End Function
Public Function DoUnauthenticatedRPC(RequestSuffix As String, Result As cCollection, Optional httpStatusText As String, Optional ByVal PayLoad As cCollection) As Boolean
Dim http As New WinHttpRequest, i As Long, ArgList As String
If Not PayLoad Is Nothing Then
For i = 0 To PayLoad.Count - 1
ArgList = ArgList & IIf(i, "&", "?") & PayLoad.KeyByIndex(i) & "=" & PayLoad.ItemByIndex(i)
Next i
End If
http.Open "GET", BitFinexApiURL & RequestSuffix & ArgList, False
http.Send
httpStatusText = http.Status & ": " & http.StatusText
If http.Status <> 200 Then Exit Function
Set Result = New_c.JSONDecodeToCollectionUTF8(http.ResponseBody)
DoUnauthenticatedRPC = True
End Function
Here's how to use the Class (I named it: cBitFinex)
Code:
Dim BitFinex As New cBitFinex
BitFinex.Init "KEY HERE", "SECRET KEY HERE"
Dim Result As cCollection, httpStatusText As String
'Unauthenticated Request
If BitFinex.DoUnauthenticatedRPC("/lendbook/btc", Result, httpStatusText) Then
Debug.Print Result.SerializeToJSONString
Else
Debug.Print httpStatusText
End If
'Authenticated Request
If BitFinex.DoAuthenticatedRPC("/balances", Result, httpStatusText) Then
Debug.Print Result.SerializeToJSONString
Else
Debug.Print httpStatusText
End If
Couldn't really test it, not having an account at the site in question.
Let me know, how it works on your end.
Olaf
Last edited by Schmidt; Apr 19th, 2015 at 02:28 AM.
Reason: corrected the result-decoding to JSONDecodeToCollectionUTF8
-
Apr 18th, 2015, 07:16 PM
#4
Re: Help communicating with web API
Wow Olaf thanks a million will go and test will post back results!
-
Apr 18th, 2015, 07:39 PM
#5
Re: Help communicating with web API
Hey Olaf ( I am trying to figure it out but no luck so far) I get an Error object variable or with block variable not set
This is the line
Code:
DoAuthenticatedRPC.Prop("httpStatus") = http.Status & ": " & http.StatusText
-
Apr 18th, 2015, 07:46 PM
#6
Re: Help communicating with web API
ok it is working (it did have my balance in the debug window) Olaf but I had to modify, if you could tell me why your code is making an error it would be fantastic, but here is the "working" version
Code:
Public Function DoAuthenticatedRPC(RequestSuffix As String, Optional ByVal PayLoad As cCollection) As cCollection
Dim sPayload_UTF8_Base64 As String, http As New WinHttpRequest
If PayLoad Is Nothing Then Set PayLoad = New_c.JSONObject
PayLoad.Prop("request") = BitFinexApiVersion & RequestSuffix
PayLoad.Prop("nonce") = CStr(New_c.Connection.UniqueID64) 'that's a time-based, increasing int64-value
sPayload_UTF8_Base64 = mCrypt.Base64Enc(PayLoad.SerializeToJSONUTF8)
http.Open "POST", BitFinexApiURL & RequestSuffix, False
http.SetRequestHeader "X-BFX-APIKEY", mBitFinexKey
http.SetRequestHeader "X-BFX-PAYLOAD", sPayload_UTF8_Base64
http.SetRequestHeader "X-BFX-SIGNATURE", mCrypt.HMAC_SHA384(sPayload_UTF8_Base64, mCrypt.VBStringToUTF8(mBitFinexSecret))
http.Send
Debug.Print StrConv(http.ResponseBody, vbUnicode)
'If http.Status = 200 Then
' Set DoAuthenticatedRPC = New_c.JSONDecodeToCollection(http.ResponseBody)
'Else
' Set DoAuthenticatedRPC = New_c.JSONObject
'End If
'DoAuthenticatedRPC.Prop("httpStatus") = http.Status & ": " & http.StatusText
-
Apr 18th, 2015, 07:49 PM
#7
Re: Help communicating with web API
Originally Posted by Max187Boucher
Hey Olaf ( I am trying to figure it out but no luck so far) I get an Error object variable or with block variable not set
This is the line
Code:
DoAuthenticatedRPC.Prop("httpStatus") = http.Status & ": " & http.StatusText
Yes, sorry - forgot to give the correct JSON-decoding-method (for UTF8-ByteContent) in the above code:
Code:
Set DoAuthenticatedRPC = New_c.JSONDecodeToCollection(http.ResponseBody)
had to be:
Code:
Set DoAuthenticatedRPC = New_c.JSONDecodeToCollectionUTF8(http.ResponseBody)
I've corrected that now in the above snippet...
Your own version, using StrConv would work only for ASCII (should work in most cases, but better to go with the original, corrected method)
Olaf
-
Apr 18th, 2015, 08:09 PM
#8
Re: Help communicating with web API
It is working 100% so far now Olaf, one last question how do I retrieve the information needed... I can get it all in one line (I guess I can split text/parse it myself) but was wondering if there is a way to call the exact (header/node/element)
I added
Code:
'class
DoAuthenticatedRPC.Prop("balance") = http.ResponseText
'form
Debug.Print Result("balance")
Code:
{"type":"deposit","currency":"btc","amount":"0.0","available":"0.0"},{"type":"exchange","currency":"btc","amount":"0.0","available":"0.0"},{"type":"exchange","currency":"usd","amount":"11111111.9999","available":"1111111.9999"}]
-
Apr 18th, 2015, 08:15 PM
#9
Re: [RESOLVED] Help communicating with web API
Thanks to Olaf this is Resolved, we can always count on you Olaf, the help is very appreciated, and thanks for your valuable (free) time!!
-
Apr 18th, 2015, 08:46 PM
#10
Re: Help communicating with web API
Originally Posted by Max187Boucher
It is working 100% so far now Olaf, one last question how do I retrieve the information needed... I can get it all in one line (I guess I can split text/parse it myself) but was wondering if there is a way to call the exact (header/node/element)
I added...
Max, could you please try with an absolutely unchanged cBitFinex-Class (as updated in #3)...
I've even added a second Public Method DoUnauthenticatedRPC to it now, so that the complete BitFinex-API is covered.
Maybe some explanations with regards to the Result-cCollection (which encapsulates the JSON-response already
in a convenient way - including proper UTF8-Unicode-decoding - so that you *don't* have to do any parsing yourself)...
The BitFinex-API-Description (about the fields in the Responses) is here: https://www.bitfinex.com/pages/api
Example, how to use the Result-Collection with an Unauthenticated RPC:
Code:
Dim BitFinex As New cBitFinex, Result As cCollection, httpStatusText As String
If BitFinex.DoUnauthenticatedRPC("/lendbook/btc", Result, httpStatusText) Then
Dim Bids As cCollection
Set Bids = Result("bids")
Dim i As Long
For i = 0 To Bids.Count - 1
Debug.Print "Arr-Index:"; i, "rate: "; Bids(i)("rate")
Debug.Print "Arr-Index:"; i, "amount: "; Bids(i)("amount")
Debug.Print "Arr-Index:"; i, "period: "; Bids(i)("period")
Debug.Print "Arr-Index:"; i, "timestamp: "; Bids(i)("timestamp")
Debug.Print "Arr-Index:"; i, "frr: "; Bids(i)("frr")
Next
Else
Debug.Print httpStatusText
End If
Example, how to use the Result-Collection with Authenticated RPC:
Code:
Dim BitFinex As New cBitFinex
BitFinex.Init "KEY HERE", "SECRET KEY HERE"
Dim Result As cCollection, httpStatusText As String
If BitFinex.DoAuthenticatedRPC("/balances", Result, httpStatusText) Then
Dim i As Long
For i = 0 To Result.Count - 1
Debug.Print "Arr-Index:"; i, "type: "; Result(i)("type")
Debug.Print "Arr-Index:"; i, "currency: "; Result(i)("currency")
Debug.Print "Arr-Index:"; i, "amount: "; Result(i)("amount")
Debug.Print "Arr-Index:"; i, "available: "; Result(i)("available")
Next i
Else
Debug.Print httpStatusText
End If
HTH
Olaf
Last edited by Schmidt; Apr 18th, 2015 at 09:46 PM.
Reason: Changed the examples, to match with the new Class in post #3
-
Apr 18th, 2015, 08:52 PM
#11
Re: [RESOLVED] Help communicating with web API
I will try it in a 15min and post back i was wondering about the unauthenticaded version which i might not use but its good to know thanks again will post back soon
-
Apr 18th, 2015, 09:10 PM
#12
Re: [RESOLVED] Help communicating with web API
I get type mismatch error
using
Code:
Option Explicit
Const BitFinexApiVersion$ = "/v1", BitFinexApiURL = "https://api.bitfinex.com" & BitFinexApiVersion
Private mBitFinexKey As String, mBitFinexSecret As String, mCrypt As cCrypt
Friend Sub Init(BitFinexKey As String, BitFinexSecret As String)
mBitFinexKey = BitFinexKey
mBitFinexSecret = BitFinexSecret
Set mCrypt = New_c.Crypt
End Sub
Public Function DoAuthenticatedRPC(RequestSuffix As String, Optional ByVal PayLoad As cCollection) As cCollection
Dim sPayload_UTF8_Base64 As String, http As New WinHttpRequest
If PayLoad Is Nothing Then Set PayLoad = New_c.JSONObject
PayLoad.Prop("request") = BitFinexApiVersion & RequestSuffix
PayLoad.Prop("nonce") = CStr(New_c.Connection.UniqueID64) 'that's a time-based, increasing int64-value
sPayload_UTF8_Base64 = mCrypt.Base64Enc(PayLoad.SerializeToJSONUTF8)
http.Open "POST", BitFinexApiURL & RequestSuffix, False
http.SetRequestHeader "X-BFX-APIKEY", mBitFinexKey
http.SetRequestHeader "X-BFX-PAYLOAD", sPayload_UTF8_Base64
http.SetRequestHeader "X-BFX-SIGNATURE", mCrypt.HMAC_SHA384(sPayload_UTF8_Base64, mCrypt.VBStringToUTF8(mBitFinexSecret))
http.Send
If http.Status = 200 Then
Set DoAuthenticatedRPC = New_c.JSONDecodeToCollectionUTF8(http.ResponseBody)
Else
Set DoAuthenticatedRPC = New_c.JSONObject
End If
DoAuthenticatedRPC.Prop("httpStatus") = http.Status & ": " & http.StatusText
End Function
Public Function DoUnauthenticatedRPC(RequestSuffix As String) As cCollection
Dim http As New WinHttpRequest
http.Open "GET", BitFinexApiURL & RequestSuffix, False
http.Send
If http.Status = 200 Then
Set DoUnauthenticatedRPC = New_c.JSONDecodeToCollectionUTF8(http.ResponseBody)
Else
Set DoUnauthenticatedRPC = New_c.JSONObject
End If
DoUnauthenticatedRPC.Prop("httpStatus") = http.Status & ": " & http.StatusText
End Function
and using
Code:
Private Sub Command1_Click()
Dim BitFinex As New cBitFinex
BitFinex.Init "Key", "Secreit Key"
Dim Result As cCollection
Set Result = BitFinex.DoAuthenticatedRPC("/balances")
If Left(Result("httpStatus"), 3) = "200" Then
Dim i As Long
For i = 0 To Result.Count - 1
Debug.Print "Arr-Index:"; i, "type: "; Result(i)("type")
Debug.Print "Arr-Index:"; i, "currency: "; Result(i)("currency")
Debug.Print "Arr-Index:"; i, "amount: "; Result(i)("amount")
Debug.Print "Arr-Index:"; i, "available: "; Result(i)("available")
Next i
Else
Debug.Print Result("httpStatus")
End If
End Sub
Edit:
I tried Result("amount") (removed the (i)) and vice versa but still not working.. not working by meaning its blank (the Result() string is blank) but no error
even tried with on error resume next nothing came out
Last edited by Max187Boucher; Apr 18th, 2015 at 09:25 PM.
-
Apr 18th, 2015, 09:15 PM
#13
Re: [RESOLVED] Help communicating with web API
I'm getting excited all I need now is to read the chart and make some algorithm that will bid/sell for me, I might open a new thread on how to read the data from your chart example you gave me a few days ago, I know it's probably simple (for you) but a bit of guidance will get me going.
-
Apr 18th, 2015, 09:31 PM
#14
Re: [RESOLVED] Help communicating with web API
got it!!
Code:
Debug.Print "Arr-Index:"; i, "type: "; Result.ItemByIndex(i)("type")
tell me if that suppose to be wrong? because it works and changed to .count - 2 (or else it threw an error because last item did not exist)
Code:
Dim i As Long
For i = 0 To Result.Count - 2
Debug.Print "Arr-Index:"; i, "type: "; Result.ItemByIndex(i)("type")
Debug.Print "Arr-Index:"; i, "currency: "; Result.ItemByIndex(i)("currency")
Debug.Print "Arr-Index:"; i, "amount: "; Result.ItemByIndex(i)("amount")
Debug.Print "Arr-Index:"; i, "available: "; Result.ItemByIndex(i)("available")
Next i
Returned:
Code:
Arr-Index: 0 type: deposit
Arr-Index: 0 currency: btc
Arr-Index: 0 amount: 0.0
Arr-Index: 0 available: 0.0
Arr-Index: 1 type: exchange
Arr-Index: 1 currency: btc
Arr-Index: 1 amount: 0.0
Arr-Index: 1 available: 0.0
Arr-Index: 2 type: exchange
Arr-Index: 2 currency: usd
Arr-Index: 2 amount: ###.###
Arr-Index: 2 available: ###.###
yes it returned the amount I changed to ###.###
Last edited by Max187Boucher; Apr 18th, 2015 at 09:35 PM.
-
Apr 18th, 2015, 09:51 PM
#15
Re: [RESOLVED] Help communicating with web API
Originally Posted by Max187Boucher
I get type mismatch error
Ok, in case of the "/balances" call, the error happened, because the JSON-result is not returned as a JSON-Object,
but as a JSON-array - and thus I cannot simply add a Key/Value pair as e.g. my: "httpStatus":"200 OK" to it.
(Key-Value-Pairs are only "addable" to a JSON-Object-Container, not to a JSON-Array-Container).
So, I've changed the stuff in post #3 again (for the last time hopefully <g>) -
and adapted the two examples in post #10 appropriately as well.
It would be really nice, when you could update the complete Class again (according to #3) -
and then maybe check the two updated examples in #10 for me too... (so that others will
find tested stuff in this thread, which will not choke anymore).
Edit: Just saw what you did in your posting above - that's a workaround which is not
necessary anymore, when the latest Class from #3 is used (usage then according to #10).
Olaf
-
Apr 18th, 2015, 10:01 PM
#16
Re: [RESOLVED] Help communicating with web API
How would I get this one Olaf... I tried btcusd, btc, usd,usdbtc, $, :btcusd, :btc.....
Code:
GET /pubticker/:symbol
.......
If BitFinex.DoUnauthenticatedRPC("/pubticker/usdbtc", Result, httpStatusText) Then
and I tried your new updated version of Post #3 and Post #10 everything works as expected no changes
-
Apr 18th, 2015, 10:25 PM
#17
Re: [RESOLVED] Help communicating with web API
Ok so I tried your alternative and it returned a json string
Code:
If BitFinex.DoUnauthenticatedRPC("/pubticker/btcusd", Result, httpStatusText) Then
Debug.Print Result.SerializeToJSONString
Else
Debug.Print httpStatusText
End If
so now I try with the function
Code:
Private Sub Command2_Click()
Dim BitFinex As New cBitFinex, Result As cCollection, httpStatusText As String
If BitFinex.DoUnauthenticatedRPC("/pubticker/btcusd", Result, httpStatusText) Then
Dim Bids As cCollection
Set Bids = Result("bids")
Dim i As Long
For i = 0 To Bids.Count - 1
Debug.Print "Arr-Index:"; i, "rate: "; Bids(i)("rate")
Debug.Print "Arr-Index:"; i, "amount: "; Bids(i)("amount")
Debug.Print "Arr-Index:"; i, "period: "; Bids(i)("period")
Debug.Print "Arr-Index:"; i, "timestamp: "; Bids(i)("timestamp")
Debug.Print "Arr-Index:"; i, "frr: "; Bids(i)("frr")
Next
Else
Debug.Print httpStatusText
End If
End Sub
says error Object Required
so if I simply use a string like this
Code:
Private Sub Command2_Click()
Dim BitFinex As New cBitFinex, Result As cCollection, httpStatusText As String
If BitFinex.DoUnauthenticatedRPC("/pubticker/btcusd", Result, httpStatusText) Then
Dim s as string
s = Result("bid")
Debug.Print "Bid: " & s
Else
Debug.Print httpStatusText
End If
End Sub
this works as expected, could we modify our function a little so it can return a simple string or array of strings?
-
Apr 18th, 2015, 10:25 PM
#18
Re: [RESOLVED] Help communicating with web API
Originally Posted by Max187Boucher
How would I get this one Olaf... I tried btcusd, btc, usd,usdbtc, $, :btcusd, :btc.....
Code:
GET /pubticker/:symbol
.......
If BitFinex.DoUnauthenticatedRPC("/pubticker/usdbtc", Result, httpStatusText) Then
and I tried your new updated version of Post #3 and Post #10 everything works as expected no changes
Ok, thanks for testing that...
As for your question above, any API should be doable now with the Class - so the following is,
how to use it in that case: according to https://www.bitfinex.com/pages/api - there's only
normal "Key-Value-Fields" in the JSON-Result-Collection, so we can enumerate the Keys
and the Values in a Loop...
Code:
Dim i As Long, BitFinex As New cBitFinex, Result As cCollection, httpStatusText As String
If BitFinex.DoUnauthenticatedRPC("/symbols", Result, httpStatusText) Then
Debug.Print vbLf; "Available Symbols:"
For i = 0 To Result.Count - 1
Debug.Print Result(i)
Next
Else
Debug.Print httpStatusText
End If
'now we make use of one of the above listed symbols (btcusd) in the next call
If BitFinex.DoUnauthenticatedRPC("/pubticker/btcusd", Result, httpStatusText) Then
Debug.Print vbLf; "Requested Result, calling: /pubticker/btcusd"
For i = 0 To Result.Count - 1
Debug.Print Result.KeyByIndex(i), Result.ItemByIndex(i)
Next
Else
Debug.Print httpStatusText
End If
Olaf
-
Apr 18th, 2015, 10:33 PM
#19
Re: [RESOLVED] Help communicating with web API
Sorry one last thing never thought about it was too excited haha
how would I post data to make a new order.. now that we got the request part covered
-
Apr 18th, 2015, 10:47 PM
#20
Re: [RESOLVED] Help communicating with web API
Originally Posted by Max187Boucher
Ok so I tried your alternative and it returned a json string
Code:
If BitFinex.DoUnauthenticatedRPC("/pubticker/btcusd", Result, httpStatusText) Then
Debug.Print Result.SerializeToJSONString
Else
Debug.Print httpStatusText
End If
That's only the output of the unparsed content of the JSON-Collection
(which works on any content, and I listed it therefore as the "generic example" in #3).
Though the whole point of JSON-Parsing-Encapsulations is, that you gain comfort
whilst reading or writing the contained Fields (in this case over a cCollection).
Originally Posted by Max187Boucher
so now I try with the function
Code:
Private Sub Command2_Click()
Dim BitFinex As New cBitFinex, Result As cCollection, httpStatusText As String
If BitFinex.DoUnauthenticatedRPC("/pubticker/btcusd", Result, httpStatusText) Then
Dim Bids As cCollection
Set Bids = Result("bids")
...
Max, when you want to work with the result-Collection directly, you have
to look at "which Named-Fields are in there first".
You can do that two ways:
- by enumerating the Keys on the Result-cCollection (per Result.KeyByIndex(i))
- by looking at the API-Documentation for the call in question on: https://www.bitfinex.com/pages/api
The latter one is recommended:
So in case of the call above: /pubticker/btcusd
The documentation says, that the Response-Result contains the following fields:
Response:
Key |
Type |
Description |
mid |
[price] |
(bid + ask) / 2 |
bid |
[price] |
Innermost bid. |
ask |
[price] |
Innermost ask. |
last_price |
[price] |
The price at which the last order executed. |
low |
[price] |
Lowest trade price of the last 24 hours |
high |
[price] |
Highest trade price of the last 24 hours |
volume |
[price] |
Trading volume of the last 24 hours |
timestamp |
[time] |
The timestamp at which this information was valid. |
And in case of this call, the Field "bid" is a normal Value-Field (Price), ...
whereas in the other call you tested: /lendbook/btc
The documentation says:
Response
Key |
Type |
Description |
bids |
[array of loan demands] |
|
rate |
[rate in % per 365 days] |
|
amount |
[decimal] |
|
period |
[days] |
minimum period for the loan |
timestamp |
[time] |
|
frr |
[yes/no] |
"Yes" if the offer is at Flash Return Rate, "No" if the offer is at fixed rate |
asks |
[array of loan offers] |
|
rate |
[rate in % per 365 days] |
|
amount |
[decimal] |
|
period |
[days] |
maximum period for the loan |
timestamp |
[time] |
|
frr |
[yes/no] |
"Yes" if the offer is at Flash Return Rate, "No" if the offer is at fixed rate |
Now we have a Field "bids", which is flagged as an array - and array-members are
contained not as a "direct accessible value-field", but over a different cCollection-
instance, which you can then "dive into" (one level deeper) and enumerate separately.
Therefore the example for /lendbook/btc did this:
Code:
'... do the call, retrieve the Result-Collection
Dim Bids As cCollection
Set Bids = Result("bids")
So, what we did above, was the retrieval of a "SubObject" of the ResultList "by Name" (Set Bids = Result("bids").
In this concrete case, there's only one second Member in the Results-Collection, the Field "asks"
(note the trailing 's' in both cases) - so, to enumerate the contents of Result("asks"), we would
do a similar thing as we did with Result("bids") - using a temporary Variable of type cCollection,
to retrieve the Result-Field-Content for the Key "asks", then enumerate its members
(the documentation is a bit "unsharp" in this case, because the listed Members belong to the
SubObjects, they are not contained directly in the Result-Collection).
Olaf
-
Apr 18th, 2015, 11:01 PM
#21
Re: [RESOLVED] Help communicating with web API
Originally Posted by Schmidt
That's only the output of the unparsed content of the JSON-Collection
(which works on any content, and I listed it therefore as the "generic example" in #3).
Though the whole point of JSON-Parsing-Encapsulations is, that you gain comfort
whilst reading or writing the contained Fields (in this case over a cCollection).
Max, when you want to work with the result-Collection directly, you have
to look at "which Named-Fields are in there first".
You can do that two ways:
- by enumerating the Keys on the Result-cCollection (per Result.KeyByIndex(i))
- by looking at the API-Documentation for the call in question on: https://www.bitfinex.com/pages/api
The latter one is recommended:
So in case of the call above: /pubticker/btcusd
The documentation says, that the Response-Result contains the following fields:
Response: Key |
Type |
Description |
mid |
[price] |
(bid + ask) / 2 |
bid |
[price] |
Innermost bid. |
ask |
[price] |
Innermost ask. |
last_price |
[price] |
The price at which the last order executed. |
low |
[price] |
Lowest trade price of the last 24 hours |
high |
[price] |
Highest trade price of the last 24 hours |
volume |
[price] |
Trading volume of the last 24 hours |
timestamp |
[time] |
The timestamp at which this information was valid. |
And in case of this call, the Field "bid" is a normal Value-Field (Price), ...
whereas in the other call you tested: /lendbook/btc
The documentation says:
Response Key |
Type |
Description |
bids |
[array of loan demands] |
|
rate |
[rate in % per 365 days] |
|
amount |
[decimal] |
|
period |
[days] |
minimum period for the loan |
timestamp |
[time] |
|
frr |
[yes/no] |
"Yes" if the offer is at Flash Return Rate, "No" if the offer is at fixed rate |
asks |
[array of loan offers] |
|
rate |
[rate in % per 365 days] |
|
amount |
[decimal] |
|
period |
[days] |
maximum period for the loan |
timestamp |
[time] |
|
frr |
[yes/no] |
"Yes" if the offer is at Flash Return Rate, "No" if the offer is at fixed rate |
Now we have a Field "bids", which is flagged as an array - and array-members are
contained not as a "direct accessible value-field", but over a different cCollection-
instance, which you can then "dive into" (one level deeper) and enumerate separately.
Therefore the example for /lendbook/btc did this:
Code:
'... do the call, retrieve the Result-Collection
Dim Bids As cCollection
Set Bids = Result("bids")
So, what we did above, was the retrieval of a "SubObject" of the ResultList "by Name" (Set Bids = Result("bids").
In this concrete case, there's only one second Member in the Results-Collection, the Field "asks"
(note the trailing 's' in both cases) - so, to enumerate the contents of Result("asks"), we would
do a similar thing as we did with Result("bids") - using a temporary Variable of type cCollection,
to retrieve the Result-Field-Content for the Key "asks", then enumerate its members
(the documentation is a bit "unsharp" in this case, because the listed Members belong to the
SubObjects, they are not contained directly in the Result-Collection).
Olaf
That makes sense, now I know how to retrieve arrays inside the json object (with your examples)
So far I got everything working except not sure about the resquest (to post data TO the website) I'm thinking with your extra parameter Payload... so I just do this
quick example of what I think it should be
Code:
Dim col As cCollection
col.Prop("symbol") = "btcusd"
col.Prop("amount") = 0.1 'would this still be a string it says decimal?
'.....
If BitFinex.DoAuthenticatedRPC("/balances", Result, httpStatusText, col) Then
'.......
Edit:
Tried this
Code:
If PayLoad Is Nothing Then Set PayLoad = New_c.JSONObject
PayLoad.Prop("request") = BitFinexApiVersion & RequestSuffix
PayLoad.Prop("nonce") = CStr(New_c.Connection.UniqueID64) 'that's a time-based, increasing int64-value
PayLoad.Prop("symbol") = "btcusd"
PayLoad.Prop("amount") = "CDec(0.1)"
PayLoad.Prop("price") = "222"
PayLoad.Prop("exchange") = "bitfinex"
PayLoad.Prop("side") = "buy"
PayLoad.Prop("type") = "exchange limit"
PayLoad.Prop("is_hidden") = 0
sPayload_UTF8_Base64 = mCrypt.Base64Enc(PayLoad.SerializeToJSONUTF8)
'........................
bad request
Last edited by Max187Boucher; Apr 19th, 2015 at 12:00 AM.
-
Apr 19th, 2015, 12:38 AM
#22
Re: [RESOLVED] Help communicating with web API
Originally Posted by Max187Boucher
So far I got everything working except not sure about the resquest (to post data TO the website) I'm thinking with your extra parameter Payload... so I just do this
quick example of what I think it should be
Code:
Dim col As cCollection
col.Prop("symbol") = "btcusd"
col.Prop("amount") = 0.1 'would this still be a string it says decimal?
'.....
If BitFinex.DoAuthenticatedRPC("/balances", Result, httpStatusText, col) Then
'.......
That's (basically) the right approach - meaning, the Methods in the Class should be used
generically (for any authenticated ot unauthenticated API) - and if Parameters are
requried, then those should be provided from outside (as in your snippet above) -
and not directly manipulated within the generic functions themselves...
Well, that said - and from what I think you want to attempt (a new order, right?) -
the Documentation says:
New order
Submit a new order.
POST /order/new
Request
Key |
Type |
Description |
symbol |
[string] |
The name of the symbol (see `/symbols`). |
amount |
[decimal] |
Order size: how much to buy or sell. |
price |
[price] |
Price to buy or sell at. Must be positive. Use random number for market orders. |
exchange |
[string] |
"bitfinex" |
side |
[string] |
Either "buy" or "sell". |
type |
[string] |
Either "market" / "limit" / "stop" / "trailing-stop" / "fill-or-kill" / "exchange market" / "exchange limit" / "exchange stop" / "exchange trailing-stop" / "exchange fill-or-kill". (type starting by "exchange " are exchange orders, others are margin trading orders) |
is_hidden |
[bool] |
true if the order should be hidden. Default is false. |
So, the first thing to check, would be the correct Request-Suffix for the call, which in this case would be the Literal:
"/order/new"
which needs to be passed...
Maybe that was the only thing you overlooked...
Here's how I would try it:
Code:
Dim BitFinex As New cBitFinex
BitFinex.Init "KEY HERE", "SECRET KEY HERE"
Dim Args As cCollection
Set Args = New_c.JSONObject
Args.Prop("symbol") = "btcusd"
Args.Prop("amount") = "0.1" 'pass it as string
Args.Prop("price") = "222"
Args.Prop("exchange") = "bitfinex"
Args.Prop("side") = "buy"
Args.Prop("type") = "exchange limit"
Args.Prop("is_hidden") = False
Debug.Print Args.SerializeToJSONString '<-Just for control-purposes, before we pass it
Dim Result As cCollection, httpStatusText As String
If BitFinex.DoAuthenticatedRPC("/order/new", Result, httpStatusText, Args) Then
Debug.Print Result("order_id")
Else
Debug.Print httpStatusText
End If
Olaf
-
Apr 19th, 2015, 01:36 AM
#23
Re: [RESOLVED] Help communicating with web API (bitfinex)
the is_hidden prop has to be true or else be excluded from the collection (because default is false, for some reason they don't accept false as a property but True works).... I got it to work properly now
Thanks Olaf I would not have made it without you that for sure.
Works
Code:
BitFinex.Init "key", "secret key"
Dim Args As cCollection
Set Args = New_c.JSONObject
Args.Prop("symbol") = "btcusd"
Args.Prop("amount") = "0.05" 'pass it as string
Args.Prop("price") = "222.2"
Args.Prop("exchange") = "bitfinex"
Args.Prop("side") = "buy"
Args.Prop("type") = "exchange limit"
Args.Prop("is_hidden") = True
Dim Result As cCollection, httpStatusText As String
If BitFinex.DoAuthenticatedRPC("/order/new", Result, httpStatusText, Args) Then
Debug.Print Result("order_id")
Else
Debug.Print httpStatusText
End If
'OR
BitFinex.Init "key", "secret key"
Dim Args As cCollection
Set Args = New_c.JSONObject
Args.Prop("symbol") = "btcusd"
Args.Prop("amount") = "0.05" 'pass it as string
Args.Prop("price") = "222.2"
Args.Prop("exchange") = "bitfinex"
Args.Prop("side") = "buy"
Args.Prop("type") = "exchange limit"
Dim Result As cCollection, httpStatusText As String
If BitFinex.DoAuthenticatedRPC("/order/new", Result, httpStatusText, Args) Then
Debug.Print Result("order_id")
Else
Debug.Print httpStatusText
End If
Edit:
Here is a little quick function I made, thought I'd post it just for the heck of it... the more examples the better!
Form code
Code:
Private Function Create_NewOrder(Optional sSymbol As String = "btcusd", _
Optional sAmount As String = "0.05", _
Optional sPrice As String = "222", _
Optional sExchange As String = "bitfinex", _
Optional sSide As String = "buy", _
Optional sType As String = "exchange limit", _
Optional bIsHidden As Boolean = False)
Dim BitFinex As New cBitFinex
BitFinex.Init "key", "secret key"
Dim Args As cCollection
Set Args = New_c.JSONObject
Args.Prop("symbol") = sSymbol
Args.Prop("amount") = sAmount
Args.Prop("price") = sPrice
Args.Prop("exchange") = sExchange
Args.Prop("side") = sSide
Args.Prop("type") = sType
If bIsHidden Then Args.Prop("is_hidden") = bIsHidden
Dim Result As cCollection, httpStatusText As String
If BitFinex.DoAuthenticatedRPC("/order/new", Result, httpStatusText, Args) Then
Debug.Print Result("order_id")
Else
Debug.Print httpStatusText
End If
End Function
With the class from Post#3
Code:
Option Explicit
Const BitFinexApiVersion$ = "/v1", BitFinexApiURL = "https://api.bitfinex.com" & BitFinexApiVersion
Private mBitFinexKey As String, mBitFinexSecret As String, mCrypt As cCrypt
Friend Sub Init(BitFinexKey As String, BitFinexSecret As String)
mBitFinexKey = BitFinexKey
mBitFinexSecret = BitFinexSecret
Set mCrypt = New_c.Crypt
End Sub
Public Function DoAuthenticatedRPC(RequestSuffix As String, Result As cCollection, Optional httpStatusText As String, Optional ByVal PayLoad As cCollection) As Boolean
Dim sPayload_UTF8_Base64 As String, http As New WinHttpRequest
If PayLoad Is Nothing Then Set PayLoad = New_c.JSONObject
PayLoad.Prop("request") = BitFinexApiVersion & RequestSuffix
PayLoad.Prop("nonce") = CStr(New_c.Connection.UniqueID64) 'that's a time-based, increasing int64-value
sPayload_UTF8_Base64 = mCrypt.Base64Enc(PayLoad.SerializeToJSONUTF8)
http.Open "POST", BitFinexApiURL & RequestSuffix, False
http.SetRequestHeader "X-BFX-APIKEY", mBitFinexKey
http.SetRequestHeader "X-BFX-PAYLOAD", sPayload_UTF8_Base64
http.SetRequestHeader "X-BFX-SIGNATURE", mCrypt.HMAC_SHA384(sPayload_UTF8_Base64, mCrypt.VBStringToUTF8(mBitFinexSecret))
http.Send
httpStatusText = http.Status & ": " & http.StatusText
If http.Status <> 200 Then Exit Function
Set Result = New_c.JSONDecodeToCollectionUTF8(http.ResponseBody)
DoAuthenticatedRPC = True
End Function
Public Function DoUnauthenticatedRPC(RequestSuffix As String, Result As cCollection, Optional httpStatusText As String, Optional ByVal PayLoad As cCollection) As Boolean
Dim http As New WinHttpRequest
http.Open "GET", BitFinexApiURL & RequestSuffix, False
http.Send
httpStatusText = http.Status & ": " & http.StatusText
If http.Status <> 200 Then Exit Function
Set Result = New_c.JSONDecodeToCollectionUTF8(http.ResponseBody)
DoUnauthenticatedRPC = True
End Function
Last edited by Max187Boucher; Apr 19th, 2015 at 02:13 AM.
Reason: Noticed I had left my API key and secret key... I removed it, and changed them on bitfinex :) just for safety
-
Apr 19th, 2015, 02:56 AM
#24
Re: [RESOLVED] Help communicating with web API (bitfinex)
Glad you have it working also with Parameter-calls (in Authenticated Mode).
For completeness, I've updated the Base-Class in post #3 one last time
(this time just a small enhancement on the Unauthenticated Method, which
now supports Parameter-Passing as well - in the same way as the other method)
Here's a usage example:
Code:
Dim BitFinex As New cBitFinex, Result As cCollection, httpStatusText As String, Args As cCollection
'first without the optional Arguments (which gives back the arrays in their full length)
If BitFinex.DoUnauthenticatedRPC("/lendbook/btc", Result, httpStatusText) Then
Debug.Print "Array-Length of bids:", Result("bids").Count
Debug.Print "Array-Length of asks:", Result("asks").Count
Else
Debug.Print httpStatusText
End If
'now the same call again, but providing the two limiting-parameters
Set Args = New_c.JSONObject
Args.Prop("limit_bids") = 5
Args.Prop("limit_asks") = 5
If BitFinex.DoUnauthenticatedRPC("/lendbook/btc", Result, httpStatusText, Args) Then
Debug.Print "Array-Length of bids:", Result("bids").Count
Debug.Print "Array-Length of asks:", Result("asks").Count
Else
Debug.Print httpStatusText
End If
Prints out:
Code:
Array-Length of bids: 24
Array-Length of asks: 50
Array-Length of bids: 5
Array-Length of asks: 5
I think with that last addition it is now a quite usable encapsulation -
and in your shoes I'd probably implement an additional small class,
wrapper-functions with a "proper name and specialized parameters" ->
one for each request-string in the Bitfinex-API you plan to use often.
E.g. the snippet above could then look something like:
Code:
Public Function GetLendBook(ResBids as cCollection, ResAsks as cCollection, Optional CurrencyString$="btc", Optional LimitBids, Optional LimitAsks)
Dim Result As cCollection, httpStatusText As String, Args As cCollection
Set Args = New_c.JSONObject
If Not IsMissing(LimitBids) then Args.Prop("limit_bids") = LimitBids
If Not IsMissing(LimitAsks) then Args.Prop("limit_asks") = LimitAsks
If BitFinex.DoUnauthenticatedRPC("/lendbook/" & CurrencyString, Result, httpStatusText, Args) Then
GetLendBook = True
Set ResBids = Result("bids")
Set ResAsks= Result("asks")
Else
LogError "GetLendBook: " & httpStatusText
End If
End Function
a.s.o. for the other functions you plan to use from that API...
Edit: Have seen now, that you already started with such Function Wrappers in your post above...
Way to go...
Olaf
Last edited by Schmidt; Apr 19th, 2015 at 03:30 AM.
-
Apr 19th, 2015, 09:25 AM
#25
Re: [RESOLVED] Help communicating with web API (bitfinex)
Thanks Olaf you've done more than enough for now, if I need more help on this which I doubt now I'll come back here and ask for help.
I will be working on the charts probably at the end of the week I see you had high/low in your chart I'll need to perform some algo to so I can try and hedge between certain prices to minimize loses and maximize profit
To be honest I looked and looked never found anything in vb6 code it was vb.net the closest but still was missing utf8/base64/sha384 and authenticate.... I was getting closer but would have never figured it out probably without you...
I hope some people will use this functional class if they can!
-
Apr 19th, 2015, 02:22 PM
#26
Re: [RESOLVED] Help communicating with web API (bitfinex)
Hey Olaf (or anyone that knows) I am running into a TimeStamp problem giving wrong date or order...
Code:
Public Function ViewOrders() As String
Dim i As Integer
Dim Result As cCollection
Dim httpStatusText As String
Dim BitFinex As New cBitFinex
BitFinex.Init sKey, sKeySecret
If BitFinex.DoAuthenticatedRPC("/orders", Result, httpStatusText) Then
For i = 0 To Result.Count - 1
Debug.Print Result.Item(i)("id"), Result.Item(i)("side"), Result(i)("price"), Result(i)("original_amount"), "TimeStamp: " & Result(i)("timestamp") & " - Date: " & DateAdd("s", Result(i)("timestamp"), #1/1/1970#)
Next
Else
Debug.Print httpStatusText
End If
End Function
This is what is returned in my debug window... but its the wrong date I placed the order on the 4/18/(around maybe 10pm)
Code:
244640779 buy 222.5 0.05 TimeStamp: 1429419783.0 - Date: 4/19/2015 5:03:03 AM
244640943 buy 221.5 0.05 TimeStamp: 1429419807.0 - Date: 4/19/2015 5:03:27 AM
244641005 buy 222.8 0.05 TimeStamp: 1429419814.0 - Date: 4/19/2015 5:03:34 AM
244650570 buy 221.0 0.05 TimeStamp: 1429421290.0 - Date: 4/19/2015 5:28:10 AM
244650600 buy 220.0 0.05 TimeStamp: 1429421293.0 - Date: 4/19/2015 5:28:13 AM
244995675 buy 224.0 0.05 TimeStamp: 1429471134.0 - Date: 4/19/2015 7:18:54 PM
Last edited by Max187Boucher; Apr 19th, 2015 at 02:58 PM.
-
Apr 19th, 2015, 05:34 PM
#27
Re: [RESOLVED] Help communicating with web API (bitfinex)
Well, these "UnixEpoch"-Timestamps are apparently in UTC.
So, simply adding the Unix-StartDate will not be enough.
SQLite for example has a nice built-in function-set for this kind of time-values -
and so you won't need to write a special converter-routine yourself - especially
not, since I'd store the retrieved WebResults in an little InMemory-DB anyways
(for easier querying later on).
Here's a small example, that shows how you can "upload" incoming values
into a DB-Table, followed by a query, which gives back "localized Dates"
from your UTC-UnixEpoch-TimeStamp-values.
Code:
Private Sub Form_Load()
Dim MemDB As cMemDB
Set MemDB = New_c.MemDB
MemDB.Exec "Create Table T(BitTimesUTC Double)"
'upload of a few Demo-Values into the MemDB-Table
With MemDB.GetRs("Select * From T Where 1=0")
.AddNew: !BitTimesUTC = 1429419783
.AddNew: !BitTimesUTC = 1429419807
.AddNew: !BitTimesUTC = 1429419814
.AddNew: !BitTimesUTC = 1429421290
.AddNew: !BitTimesUTC = 1429421293
.AddNew: !BitTimesUTC = 1429471134
.UpdateBatch
End With
'now the read-direction, using SQLites DateTime-function for the conversion into localtime
With MemDB.GetRs("Select DateTime(BitTimesUTC, 'unixepoch', 'localtime') As BitTimesLOC From T")
Do Until .EOF
Debug.Print CDate(!BitTimesLOC)
.MoveNext
Loop
End With
End Sub
Here's the documentation for the Date- and Time-Functions in SQLite:
http://www.sqlite.org/lang_datefunc.html
Olaf
-
Apr 19th, 2015, 08:39 PM
#28
Re: [RESOLVED] Help communicating with web API (bitfinex)
Originally Posted by Schmidt
Well, these "UnixEpoch"-Timestamps are apparently in UTC.
So, simply adding the Unix-StartDate will not be enough.
SQLite for example has a nice built-in function-set for this kind of time-values -
and so you won't need to write a special converter-routine yourself - especially
not, since I'd store the retrieved WebResults in an little InMemory-DB anyways
(for easier querying later on).
Here's a small example, that shows how you can "upload" incoming values
into a DB-Table, followed by a query, which gives back "localized Dates"
from your UTC-UnixEpoch-TimeStamp-values.
Code:
Private Sub Form_Load()
Dim MemDB As cMemDB
Set MemDB = New_c.MemDB
MemDB.Exec "Create Table T(BitTimesUTC Double)"
'upload of a few Demo-Values into the MemDB-Table
With MemDB.GetRs("Select * From T Where 1=0")
.AddNew: !BitTimesUTC = 1429419783
.AddNew: !BitTimesUTC = 1429419807
.AddNew: !BitTimesUTC = 1429419814
.AddNew: !BitTimesUTC = 1429421290
.AddNew: !BitTimesUTC = 1429421293
.AddNew: !BitTimesUTC = 1429471134
.UpdateBatch
End With
'now the read-direction, using SQLites DateTime-function for the conversion into localtime
With MemDB.GetRs("Select DateTime(BitTimesUTC, 'unixepoch', 'localtime') As BitTimesLOC From T")
Do Until .EOF
Debug.Print CDate(!BitTimesLOC)
.MoveNext
Loop
End With
End Sub
Here's the documentation for the Date- and Time-Functions in SQLite:
http://www.sqlite.org/lang_datefunc.html
Olaf
Quick question on your MemDB, Olaf, does it clean itself upon closing the app? Or do I need to set it to = nothing to clear it up from memory?
Edit:
So far, I only need the date/time and your DB example does that so I decided to do it like this for the moment until I learn more about SQL.
Here is my modified version
Code:
Private Function TimeStampDate(ByVal sTimeStamp As Double) As Date
Dim MemDB As cMemDB
Set MemDB = New_c.MemDB
MemDB.Exec "Create Table T(BitTimesUTC Double)"
With MemDB.GetRs("Select * From T Where 1=0")
.AddNew: !BitTimesUTC = sTimeStamp
.UpdateBatch
End With
With MemDB.GetRs("Select DateTime(BitTimesUTC, 'unixepoch', 'localtime') As BitTimesLOC From T")
TimeStampDate = CDate(!BitTimesLOC)
End With
Set MemDB = Nothing
End Function
Works like a charm!
Last edited by Max187Boucher; Apr 19th, 2015 at 10:32 PM.
-
Apr 19th, 2015, 10:59 PM
#29
Re: [RESOLVED] Help communicating with web API (bitfinex)
Originally Posted by Max187Boucher
Quick question on your MemDB, Olaf, does it clean itself upon closing the app? Or do I need to set it to = nothing to clear it up from memory?
Upon Process-Termination, any memory-allocation which happened inside a Process is cleaned up of course.
During Runtime, there's an (SQLite-library-internal) Cache-allocation of a few Megabyte (8MB or so initially),
and this cache is re-used by new upstarting SQLite-MemDBs (or -FileDBs) - but if you insert 100000
records into 10 different MemDB-Tables each, then these 8MB initial Memory within the SQLite-lib will
of course grow (all that data has to sit somewhere) - but its consumption is comparably lean, due to UTF8-
encoding (less than in an ADO-Recordset for example, where Strings are stored with 16Bit-per-WChar).
You might want to test the Mem-Consumption (and the proper freeing) with this
code-snippet (slightly varying from the example above) - where I create (and destroy)
a MemDB 10 times in a loop (inserting 10000 Records in each of the 10 Runs)...
Maybe compile and take a look over the TaskManager... The Mem-consumption should
remain constant, no matter how often you click the Form (in my test it swung itself in
at roughly 14MB - no Handle- or other leakage observable).
Code:
Option Explicit
Private Sub Form_Click()
Dim i As Long
For i = 1 To 10
TestMemDB
Caption = i
Next i
MsgBox "Test-Method finished (10 times create, fill, destroy of a MemDB-instance)"
End Sub
Private Sub TestMemDB()
Dim MemDB As cMemDB
Set MemDB = New_c.MemDB
MemDB.Exec "Create Table T(BitTimesUTC Double)"
Dim i As Long, StartSecond As Double
StartSecond = 1429419783
With MemDB.GetRs("Select * From T Where 1=0")
For i = 1 To 10000
.AddNew: .Fields(0).Value = StartSecond + 1
Next
.UpdateBatch
End With
End Sub 'at this point, the MemDB-Obj is going out of scope and internally cleaned up
I use MemDBs quite often in my own Apps - and was never biten...
(a small worst-case calculation, with the maximum expected amount of records
times average ColumnCount over all tables you might create, will help... as e.g.:
If you plan to use about 10 tables, with an average of 10 Columns each
and an average recordcount of 20000 records each, then the calculation is:
10 * 10 * 20000 * 80Bytes on average per Field... so this amounts to 160MB roughly -
if you plan to hold that same amount of data in e.g. UDT-Arrays instead, then it is
questionable whether it is lower in total (mem-allocation-wise) - because the same thing
I mentioned already with ADO-Rs' applies also for VBs-UDTs (or Arrays of Type String)
UTF8-based String-Storage will take up (usually) only half the storage of UTF-16.
(and String-Fields make always a good amount of the Fields in most scenarios).
What's also nice (in case you start-out with a MemDB from the very beginning,
instead of using Arrays or other things) - you can write a MemDB-instance with
one line of code (MemDB.Cnn.CopyDataBase) into a SingleFile-DB in the FileSystem
(including all Created Tables, Indexes and Contents of your MemDB) - this way
your very own "Single-File-Document-Format" for your whole Application-State
(or other things) is always only "one line of code away".
Nearly forgotten...
And no, there's no Close-Method (neither on a normal SQLite-cConnection,
nor on a cRecordset - and also not on a cMemDB - which is just a convenience-wrapper
around a normal cConnection) - all instances clean themselves up internally, when
they go out of scope as the COM-Objects they are - (when the last reference-variable
which points to them, is set to nothing)...
Olaf
Last edited by Schmidt; Apr 19th, 2015 at 11:11 PM.
-
Apr 19th, 2015, 11:15 PM
#30
Re: [RESOLVED] Help communicating with web API (bitfinex)
Thanks for the information I will keep in mind if I use a MemDB...
So far this is what I made... works good so far
Module Code:
Code:
Option Explicit
Const sKey As String = "Key Here"
Const sKeySecret As String = "Secret Key Here"
Public Enum enumTicker
Mid = 0
Bid = 1
Ask = 2
LastPrice = 3
low = 4
high = 5
Volume = 6
End Enum
Public Function Ticker(GetTickerPrice As enumTicker) As String
Dim Result As cCollection
Dim httpStatusText As String
Dim BitFinex As New cBitFinex
If BitFinex.DoUnauthenticatedRPC("/pubticker/btcusd", Result, httpStatusText) Then
Select Case GetTickerPrice
Case 0
Ticker = Format(Result("mid"), "0.00")
Case 1
Ticker = Format(Result("bid"), "0.00")
Case 2
Ticker = Format(Result("ask"), "0.00")
Case 3
Ticker = Format(Result("last_price"), "0.00")
Case 4
Ticker = Format(Result("low"), "0.00")
Case 5
Ticker = Format(Result("high"), "0.00")
Case 6
Ticker = Format(Result("volume"), "0.00")
End Select
Else
Ticker = httpStatusText
End If
End Function
Public Function NewOrder(Price As String, Amount As String, BuyOrSell As String, Optional sType As String = "exchange limit", Optional sSymbol As String = "btcusd", Optional sExchange As String = "bitfinex", Optional bIsHidden As Boolean = False) As String
Dim Args As cCollection
Dim Result As cCollection
Dim httpStatusText As String
Dim BitFinex As New cBitFinex
BitFinex.Init sKey, sKeySecret
Set Args = New_c.JSONObject
Args.Prop("symbol") = sSymbol
Args.Prop("amount") = Amount
Args.Prop("price") = Price
Args.Prop("exchange") = sExchange
Args.Prop("side") = LCase(BuyOrSell)
Args.Prop("type") = LCase(sType)
If bIsHidden Then Args.Prop("is_hidden") = bIsHidden
If BitFinex.DoAuthenticatedRPC("/order/new", Result, httpStatusText, Args) Then
NewOrder = Result("order_id")
Else
NewOrder = httpStatusText
End If
End Function
Public Function UpdateOrders(OrderList As ListBox) As String
Dim i As Integer
Dim Result As cCollection
Dim httpStatusText As String
Dim BitFinex As New cBitFinex
BitFinex.Init sKey, sKeySecret
If BitFinex.DoAuthenticatedRPC("/orders", Result, httpStatusText) Then
OrderList.Clear
For i = 0 To Result.Count - 1
OrderList.AddItem Result.Item(i)("id") & vbTab & _
Result.Item(i)("side") & vbTab & _
Result(i)("price") & vbTab & _
Round(Result(i)("original_amount"), 2) & vbTab & _
Format(TimeStampDate(Result(i)("timestamp")), "mmm dd, yyyy @ hh:mm ampm")
Next
UpdateOrders = "Successful"
Else
UpdateOrders = httpStatusText
End If
End Function
Private Function TimeStampDate(ByVal sTimeStamp As Double) As Date
Dim MemDB As cMemDB
Set MemDB = New_c.MemDB
MemDB.Exec "Create Table T(BitTimesUTC Double)"
With MemDB.GetRs("Select * From T Where 1=0")
.AddNew: !BitTimesUTC = sTimeStamp
.UpdateBatch
End With
With MemDB.GetRs("Select DateTime(BitTimesUTC, 'unixepoch', 'localtime') As BitTimesLOC From T")
TimeStampDate = CDate(!BitTimesLOC)
End With
End Function
Public Function GetOrderInfo(sOrderID As String) As String
Dim Result As cCollection
Dim httpStatusText As String
Dim BitFinex As New cBitFinex
Dim OrderID As cCollection
BitFinex.Init sKey, sKeySecret
Set OrderID = New_c.JSONObject
OrderID.Prop("order_id") = Val(sOrderID)
If BitFinex.DoAuthenticatedRPC("/order/status", Result, httpStatusText, OrderID) Then
Debug.Print Result.Item("is_live")
Debug.Print Result.Item("price")
Debug.Print Result.Item("original_amount")
Else
GetOrderInfo = httpStatusText
End If
End Function
Public Function CancelOrder(Optional sOrderID As String, Optional CancelAll As Boolean = False)
Dim Result As cCollection
Dim httpStatusText As String
Dim BitFinex As New cBitFinex
Dim OrderID As cCollection
BitFinex.Init sKey, sKeySecret
If CancelAll Then
BitFinex.DoAuthenticatedRPC "/order/cancel/all", Result, httpStatusText, OrderID
Else
Set OrderID = New_c.JSONObject
OrderID.Prop("order_id") = Val(sOrderID)
BitFinex.DoAuthenticatedRPC "/order/cancel", Result, httpStatusText, OrderID
End If
CancelOrder = httpStatusText
End Function
Form Code:
Code:
Option Explicit
Private Sub cmdBuy_Click()
NewOrder txtPrice.Text, txtAmount.Text, "buy", cmbOrder.Text
End Sub
Private Sub cmdSell_Click()
NewOrder txtPrice.Text, txtAmount.Text, "sell", cmbOrder.Text
End Sub
Private Sub Command1_Click()
'Cancel Single Order
CancelOrder Left(lstOrders.List(lstOrders.ListIndex), 9), True
'Cancel All Orders
CancelOrder , True
End Sub
Private Sub Command2_Click()
UpdateOrders lstOrders
End Sub
Private Sub lstOrders_Click()
GetOrderInfo Left(lstOrders.List(lstOrders.ListIndex), 9)
End Sub
Private Sub Timer1_Timer()
Static LastMid As String
Dim sTicker As String
sTicker = Ticker(Mid)
If LastMid <> sTicker Then
LastMid = sTicker
lstPrice.AddItem sTicker
End If
lblLow.Caption = Ticker(low)
lblHigh.Caption = Ticker(high)
UpdateOrders lstOrders
End Sub
and of course the Magical Olaf Class in Post #3
Of course I got lots to do still if anyone is interested at least I added a couple examples to play with(array/nonarray)
Last edited by Max187Boucher; Apr 19th, 2015 at 11:25 PM.
-
Apr 19th, 2015, 11:36 PM
#31
Re: [RESOLVED] Help communicating with web API (bitfinex)
Originally Posted by Max187Boucher
So far this is what I made... works good so far
Yep, nice code...
Just one last suggestion - when you use a Class-Encapsulation instead of the
Module-Code you have so far, you could spare yourself the BitFinex-
instantiation (and initialization with the two Keys) in each Function-Call,
by just doing that in Class_Initialize...
E.g. when you name it cBitFinexWrap - and then place a global Variable as this...
...in a Module:
Code:
Public gBF As New cBitFinexWrap
And this within the Class-Wrapper cBitFinexWrap:
Code:
Private BitFinex As New cBitFinex 'declaration at Class-Level
Private Sub Class_Initialize()
BitFinex.Init "MyKey", "MyKeySecret" 'direct initialization at Class-Startup
End Sub
Then you can remove all Procedure-local BitFinex-Class-inits (and declarations)
within your implementations in that Class.
Olaf
-
Apr 19th, 2015, 11:38 PM
#32
Re: [RESOLVED] Help communicating with web API (bitfinex)
Not sure why I didn't think about that one i'll remove them next time i work on it
-
Apr 20th, 2015, 02:01 AM
#33
Re: [RESOLVED] Help communicating with web API (bitfinex)
Originally Posted by Max187Boucher
Not sure why I didn't think about that one i'll remove them next time i work on it
Just noticed (after a closer look) that you're using the MemDB in a converter-function
which works at the "single-value-level".
That's quite inefficient, to create a MemDB-instance (and a table etc.) for each little conversion.
If you want to use it this way further, I'd at least change it to:
Code:
Private Function TimeStampDate(ByVal sTimeStamp As Double) As Date
Static MemDB As cMemDB, Cmd As cSelectCommand
If MemDB Is Nothing Then
Set MemDB = New_c.MemDB
Set Cmd = MemDB.CreateSelectCommand("Select DateTime(?, 'unixepoch', 'localtime')")
End If
Cmd.SetDouble 1, sTimeStamp 'fill the first question-mark-slot with the proper value
TimeStampDate = CDate(Cmd.Execute.Fields(0).Value)
End Function
Which then works about 12 times as fast, since it avoids the instancing on every call -
and doesn't create any Table anymore (the SQLite-SQL parser can be used entirely
without any DB-Tables to evaluate simple expressions or functions).
You currently use this function in your:
Code:
Public Function UpdateOrders(OrderList As ListBox) As String
A better (and much faster, as well as elegant way) would be, to use the MemDB in
Table-Mode again, and first beam up all your values into it (in your result-loop).
Then you can select a Recordset from the Table and update e.g. an MSHFlexGrid directly in one line
(instead of adding items into a VB.ListBox)...
Here's some TestCode, which can run in a separate VB-TestProject
(just ensure, it has a Form with an MSHFlexGrid1 on it - and the RC5-reference,
the Bitfinex-parts were commented out for this test)
Code:
Option Explicit
Private Sub Form_Load()
UpdateOrders MSHFlexGrid1
MSHFlexGrid1.ColWidth(4) = 1400
MSHFlexGrid1.ColWidth(5) = 2200
End Sub
Public Function UpdateOrders(OrderList As MSHFlexGrid) As String
Dim i As Integer
Dim Result As cCollection, Item As cCollection
Dim httpStatusText As String
'Dim BitFinex As New cBitFinex
Static MemDB As cMemDB
If MemDB Is Nothing Then Set MemDB = New_c.MemDB
' BitFinex.Init sKey, sKeySecret
' If BitFinex.DoAuthenticatedRPC("/orders", Result, httpStatusText) Then
'**** just to simulate a response from the server instead of the real thing
Set Result = New_c.JSONArray
Result.Prop(0) = New_c.JSONObject
Result.Prop(0).Prop("id") = "id 1"
Result.Prop(0).Prop("side") = "side 1"
Result.Prop(0).Prop("price") = "1234.56"
Result.Prop(0).Prop("original_amount") = "12345.6789"
Result.Prop(0).Prop("timestamp") = "1429419783"
'**** end of result-simulation
MemDB.Exec "Drop Table If Exists T" 'delete the table and the values it might contain from the last round
MemDB.Exec "Create Table T(id Text, side Text, price Text, original_amount Text, timestamp Text)" 'all fields to Text, to keep it simple
With MemDB.CreateCommand("Insert Into T Values(?,?,?,?,?)") '5 "questionmark-slots", one for each Field in the Table
For i = 0 To Result.Count - 1
Set Item = Result.Item(i) 'resolve the Collection-Sub-Object once, before accessing its Fields
.SetText 1, Item("id")
.SetText 2, Item("side")
.SetText 3, Item("price")
.SetText 4, Item("original_amount")
.SetText 5, Item("timestamp")
.Execute 'write the current record-content (our 5 fields we just placed in the slot-numbers) into the Table T
Next
End With
Const SQL$ = "Select id, side, price, Round(original_amount, 2) As original_amount, " & _
"Format$(DateTime(timestamp, 'unixepoch','localtime'), 'mmm dd, yyyy @ hh:mm AM/PM') As timestamp From T"
Set OrderList.DataSource = MemDB.GetRs(SQL).DataSource 'now update the HFlexGrid with all the records in one go
UpdateOrders = "Successful"
' Else
' UpdateOrders = httpStatusText
' End If
End Function
Here's a screenshot of the result:
Since I'm at it (but that's just a matter of taste, not performance-relevant or something)
For those who have a more "horizontal coding-style" like me (some prefer it more vertically <g>)
the usage of the Choose-Function is sometimes handy, to resolve from Enum-Values to String-representations:
Code:
Public Function Ticker(TickerPrice As enumTicker) As String
Dim Result As cCollection
Dim httpStatusText As String
Dim BitFinex As New cBitFinex
If BitFinex.DoUnauthenticatedRPC("/pubticker/btcusd", Result, httpStatusText) Then
Ticker = Format(Result(Choose(TickerPrice + 1, "mid", "bid", "ask", "last_price", "low", "high", "volume")), "0.00")
Else
Ticker = httpStatusText
End If
End Function
But as said, that's only cosmetic stuff, which might or might not be to someones personal taste...
Olaf
Last edited by Schmidt; Apr 20th, 2015 at 02:05 AM.
-
Apr 24th, 2015, 10:54 PM
#34
-
Apr 25th, 2015, 10:25 AM
#35
Re: [RESOLVED] Help communicating with web API (bitfinex)
Originally Posted by Max187Boucher
I am not good with DB stuff, specially memDB so I'm not sure if I did it correctly but its working.
I will update it eventually
Maybe a few suggestions in that regard...
Your mRequest.bas module is looking nice so far (codewise) - though from an architectural point of view,
you should consider the case (e.g. when you plan to ship this as a shareware-App or something...)
that possibly a few Users could have more than one account on BitFinex - so, encapsulating
the Code you have in a Class instead of a Module, you would take that already "into account"...
(just creating a new Class-Instance for each account, storing those potentially multiple Account-instances
in a Project-global Collection-Class later on, or an in an Array: BFAccounts() As cBFAccount ...).
So - a proper name for such a Class-Encapsulation would be e.g.: cBFAccount
The Class contains the Functions of your module mRequest.bas - but I've also
put the MemDB-Instance into this Class, to have "isolated" MemDB-instances
for each Account.
Code:
Option Explicit
Public Enum enumTicker
Mid = 0
Bid = 1
Ask = 2
LastPrice = 3
low = 4
high = 5
Volume = 6
End Enum
Public BitFinex As cBitFinex, MemDB As cMemDB 'both Variables are reachable from outside, because defined Public
Private Sub Class_Initialize()
Set MemDB = New_c.MemDB 'create a new MemDB-Instance for each cBFAccount-ClassInstance
'create an Orders Table which gets periodically synchronized from the Web
'the definition below is basically the same as a MemDB.Exec "Create Table Orders(...)"-statement,
'but it does this more "vertically" - easier to add new Fields - and more resembling a VB-TypeDef statement
With MemDB.NewFieldDefs
.Add "id Text"
.Add "side Text"
.Add "price Text"
.Add "original_amount Text"
.Add "timestamp Text"
End With
MemDB.CreateTable "Orders"
'create a View (named vwOrders), which defines the formatted output of the Field-List of the Orders-Table
'later on, you can use this ViewName as a shortcut -> as e.g. MemDB.GetRs("Select * From vwOrders")
MemDB.Exec "Create View vwOrders As " & _
"Select id, side, price, Format$(original_amount,'0.00') As original_amount, Format$(DateTime(timestamp, 'unixepoch','localtime'), 'mmm dd, yyyy @ hh:mm AM/PM') As timestamp From Orders"
End Sub
Public Sub BitFinex_Init(API_KEY As String, API_SECRET_KEY As String)
Set BitFinex = New cBitFinex
BitFinex.Init API_KEY, API_SECRET_KEY
End Sub
Public Function Ticker(TickerPrice As enumTicker) As String
Dim Result As cCollection
Dim httpStatusText As String
If BitFinex.DoUnauthenticatedRPC("/pubticker/btcusd", Result, httpStatusText) Then
Ticker = Format(Result(Choose(TickerPrice + 1, "mid", "bid", "ask", "last_price", "low", "high", "volume")), "0.00")
Else
Ticker = httpStatusText
End If
End Function
Public Function NewOrder(Price As String, Amount As String, BuyOrSell As String, Optional sType As String = "exchange limit", Optional sSymbol As String = "btcusd", Optional sExchange As String = "bitfinex", Optional bIsHidden As Boolean = False) As String
Dim Args As cCollection
Dim Result As cCollection
Dim httpStatusText As String
Set Args = New_c.JSONObject
Args.Prop("symbol") = sSymbol
Args.Prop("amount") = Amount
Args.Prop("price") = Price
Args.Prop("exchange") = sExchange
Args.Prop("side") = LCase(BuyOrSell)
Args.Prop("type") = LCase(sType)
If bIsHidden Then Args.Prop("is_hidden") = bIsHidden
If BitFinex.DoAuthenticatedRPC("/order/new", Result, httpStatusText, Args) Then
NewOrder = Result("order_id")
Else
NewOrder = httpStatusText
End If
End Function
Public Function UpdateOrders() As String
Dim Result As cCollection
Dim R As cCollection 'define the Type of the *Item* the Result-Collection contains (in this case it is other cCollection-instances)
Dim httpStatusText As String
If BitFinex.DoAuthenticatedRPC("/orders", Result, httpStatusText) Then
MemDB.Exec "Delete From Orders" 'cleanup all existing records from the Orders-Table (since we got more current, new content in the Result-Collection)
For Each R In Result 'we can iterate over the Items in the Result-Collection also per For Each
'MemDB.ExecCmd is a convenience-method to easier handle CommandObjects (first param gets the SQL, followed by the Values for the '?' slots)
MemDB.ExecCmd "Insert Into Orders Values(?,?,?,?,?)", R("id"), R("side"), R("price"), R("original_amount"), R("timestamp")
Next
UpdateOrders = "Successful"
Else
UpdateOrders = httpStatusText
End If
End Function
Public Function GetOrderInfo(sOrderID As String) As String
Dim Result As cCollection
Dim httpStatusText As String
Dim OrderID As cCollection
Set OrderID = New_c.JSONObject
OrderID.Prop("order_id") = Val(sOrderID)
If BitFinex.DoAuthenticatedRPC("/order/status", Result, httpStatusText, OrderID) Then
Debug.Print Result.Item("is_live")
Debug.Print Result.Item("price")
Debug.Print Result.Item("original_amount")
Else
GetOrderInfo = httpStatusText
End If
End Function
Public Function CancelOrder(Optional sOrderID As String, Optional CancelAll As Boolean = False)
Dim Result As cCollection
Dim httpStatusText As String
Dim OrderID As cCollection
If CancelAll Then
BitFinex.DoAuthenticatedRPC "/order/cancel/all", Result, httpStatusText, OrderID
Else
Set OrderID = New_c.JSONObject
OrderID.Prop("order_id") = Val(sOrderID)
BitFinex.DoAuthenticatedRPC "/order/cancel", Result, httpStatusText, OrderID
End If
CancelOrder = httpStatusText
End Function
A few more comments to the MemDB-instance, which is contained in this Class:
Its lifetime is now bound to the lifetime of its hosting cBFAccount-Class -
so - in case we talk about a single BitFinex-Account - and you create it
for example in a modMain.bas-Module variable as:
Code:
Public MyAccount As cBFAccount
Sub Main()
Set MyAccount = New cBFAccount
MyAccount.BitFinex_Init My_Key, My_Secret_Key
End Sub
The MemDB-instance is created (along with its Tables) in Class_Initialize
of its hosting Class - and will live as long as the MyAccount-ClassInstance lives
(usually as long as the App lives, unless you set the MyAccount-Variable
to Nothing a bit earlier than on App-Shutdown).
Anytime you need to request Data from this "Account-specific MemDB", you can do
(e.g. from within a Form, which contains a MSHFlexGrid)...
Code:
Private Sub UpdateOrdersGrid(HFlex As MSHFlexGrid)
Set HFlex.DataSource = MyAccount.MemDB.GetRs("Select * From vwOrders Order By timestamp Desc").DataSource
End Sub
to show a listing, ordered by descending timestamps (newest first)...
or alternatively use a listing which is ordered by id in ascending order (as shown below).
Code:
Private Sub UpdateOrdersGrid(HFlex As MSHFlexGrid)
Set HFlex.DataSource = MyAccount.MemDB.GetRs("Select * From vwOrders Order By id Asc").DataSource
End Sub
I think these short SQL-snippets show, why I removed the passing of "concrete GUI-Controls"
from your methods in mRequest.bas (and introduced a View-Definition in Class_Initialize of cBFAccount).
It's better to make the code in such "Data-Classes" independent from any Control-Types, to keep
them flexible to use with *any* kind of GUI-ListControls.
For a "multicolumn-view", you could use also the VB6-DataGrid- or a ListView-Control as a visualizing container -
but also a normal VB6-ListBox, as in the example below, to e.g. show only the Order-timestamps in the listbox,
and using Order-id as the ListBox-ItemData (to retrieve details later in a ListBox-Click-Event):
Code:
Private Sub UpdateOrdersLB(LB As ListBox)
LB.Clear
'restrict the returned Rs to contain only the Fields: id and timestamp
With MyAccount.MemDB.GetRs("Select id, timestamp From vwOrders Order By timestamp Desc")
Do Until .EOF
LB.AddItem !timestamp
LB.ItemData(LB.NewIndex) = !id
.MoveNext
Loop
End With
End Sub
So the MemDB is acting as a "universal Data-Container" which can host more than one Table
(e.g. your Ticker-Data could be stored in a Ticker-Table as well) - and since MemDB is
already "exposed Publically" (as a Property of your Account-ClassInstance), you can
retrieve Data (Recordsets) from its Data-Tables any time you choose to in your GUI-code,
ordered, filtered, restricted to a few fields of the table - definable with great flexibility
over the SQL-Select-string.
All you have to do is, to keep the Data in MemDB "up-to-date" (in proper intervals).
E.g. using a Timer on your Main-Form you would simply have to do:
Code:
Private Sub tmrUpdateLocalAccountData_Timer()
MyAccount.UpdateOrders
'MyAccount.UpdateTickerData
End Sub
The above Timer-based Data-Refreshing can act entirely independent from your GUIs ListControl-Refreshes
(they just ensure, that anytime you "reach into the MemDB", the Data is "quite recent").
Olaf
Last edited by Schmidt; Apr 25th, 2015 at 10:34 AM.
-
Apr 25th, 2015, 10:50 AM
#36
Re: [RESOLVED] Help communicating with web API (bitfinex)
I'm not sure how the (bizarre to my eye) convention of naming a VB6 Class with a "c" prefix ever came from.
Normally a "hungarian prefix" is meant to indicate the data type and not... module type? So cBFAccount seems like a really odd choice. Why not BFAccount instead?
After all we have Collection, TextBox, Command, etc. rather than cCollection, cTextBox, cCommand, etc. So why on Earth would one create new classes named that way? I just don't see the benefit and it seems to jar the eye and not fit with normal VB naming conventions at all.
What am I missing? There must be some advantage I'm unaware of.
-
Apr 25th, 2015, 11:50 AM
#37
Re: [RESOLVED] Help communicating with web API (bitfinex)
Originally Posted by dilettante
I'm not sure how the (bizarre to my eye) convention of naming a VB6 Class with a "c" prefix ever came from.
Normally a "hungarian prefix" is meant to indicate the data type and not... module type?
A ClassName *is* a user-definable DataType (as are Enums, or "normal TypeDefs" - and as are
Form-Classes, which I prefix with 'f' ...and also UserControl-Classes, which I prefix with 'uc' for example).
Other Class-Prefixes I use are e.g.:
- 'cw' for WidgetClasses (similar to the 'uc' prefixing in case of normal VB-UserControls)
- 'cf' for cWidgetForm-Classes (similar to the 'f' prefixing in case of normal VB-Forms)
I've explained the (for me obvious) advantages already in a reply to you here (in posting #10):
http://www.vbforums.com/showthread.p...=1#post4473729
But after all it's a matter of personal taste (easily changeable to your own naming-scheme) -
important perhaps only, what Bonnie West mentioned in the above linked thread:
"Be consistent about it in your own CodeBase".
Olaf
-
Apr 26th, 2015, 06:47 PM
#38
Re: [RESOLVED] Help communicating with web API (bitfinex)
I have changed to your suggestions which look a lot nicer and clearer (coding wise).
I had a small issue tho (not on your part) but it "lags" when sending the request through http... would it be possible to make the cBitFinex class call the http request on a different thread so my app does not "freeze until request is processed" I thought to put a timeout but it seems like it still lags but not as long and sometime does not have enough time to get the information before it times out.... I know you RC5 has multithread well how would I use it for this?
Note: My computer is a bit far from my wireless modem (thanks to the great ISP service that didn't want to put it where I wanted the modem "in the middle of the house, and not in the furthest corner")
Maybe that is why it lags a bit, but still multithread simply for the bitfinex request would save my GUI from not responding.
Form Code:
Code:
Private BFAccount() As cBFAccount
Private Sub cmdAddAccount_Click()
Add_BFAccount sKey, sKeySecret
End Sub
Private Sub cmdBuy_Click()
BFAccount(0).NewOrder txtPrice.Text, txtAmount.Text, "buy", cmbOrder.Text
End Sub
Private Sub cmdSell_Click()
BFAccount(0).NewOrder txtPrice.Text, txtAmount.Text, "sell", cmbOrder.Text
End Sub
Private Sub Command1_Click()
'Cancel Single Order
BFAccount(0).CancelOrder Left(lstOrders.List(lstOrders.ListIndex), 9)
'Cancel All Orders
'BFAccount(0).CancelOrder , True
End Sub
Private Sub lstOrders_Click()
BFAccount(0).GetOrderInfo Left(lstOrders.List(lstOrders.ListIndex), 9)
End Sub
Private Sub Add_BFAccount(bfKey As String, bfKeySecret As String)
If UBound(BFAccount) = 0 Then
Set BFAccount(0) = New cBFAccount
BFAccount(0).BitFinex_Init bfKey, bfKeySecret
Else
ReDim Preserve BFAccount(UBound(BFAccount) + 1)
Set BFAccount(UBound(BFAccount)) = New cBFAccount
BFAccount(UBound(BFAccount)).BitFinex_Init bfKey, bfKeySecret
End If
End Sub
Private Sub UpdateOrdersGrid(HFlex As MSHFlexGrid)
Set HFlex.DataSource = BFAccount(0).MemDB.GetRs("Select * From vwOrders Order By timestamp Desc").DataSource
End Sub
Private Sub Form_Load()
ReDim BFAccount(0)
End Sub
Private Sub Timer1_Timer()
Static LastMid As String
Dim sTicker As String
sTicker = BFAccount(0).Ticker(Mid)
If LastMid <> sTicker Then
LastMid = sTicker
lstTrend.AddItem sTicker
End If
lblLow.Caption = BFAccount(0).Ticker(low)
lblHigh.Caption = BFAccount(0).Ticker(high)
UpdateOrdersGrid flxOrderList
End Sub
And also made the two modules into a class cBFAccount like you suggested
I don't know if BitFinex would allow two account on one IP tho... proxy would work though but we will leave this for later if required... we'll just make it so it is available but not coded yet (for later use so we don't have to change the whole classes and code)
Edit:
I can't seem to find on the API page where it shows how to get the Bids/Asks list like on the webpage, I can get them webscraping but I'm using the API there must be something I'm missing, its not book/lendbook do you know which one it could be?
Last edited by Max187Boucher; Apr 26th, 2015 at 09:06 PM.
-
Apr 27th, 2015, 03:08 AM
#39
Re: [RESOLVED] Help communicating with web API (bitfinex)
Originally Posted by Max187Boucher
Edit:
I can't seem to find on the API page where it shows how to get the Bids/Asks list like on the webpage, I can get them webscraping but I'm using the API there must be something I'm missing, its not book/lendbook do you know which one it could be?
Look at the "Orderbook".
-
Apr 27th, 2015, 03:41 AM
#40
Re: [RESOLVED] Help communicating with web API (bitfinex)
Yep, Orderbook is quite similar to the Lendbook-query, which we already have an example
(further above somewhere)...
Here' Lendbook in conjunction with the MemDB-storage:
Code:
Dim BitFinex As New cBitFinex, Result As cCollection, httpStatusText As String, Args As cCollection
If BitFinex.DoUnauthenticatedRPC("/lendbook/btc", Result, httpStatusText) Then
Dim R As cCollection
MemDB.Exec "Delete From LendbookBids"
For Each R In Result("bids")
MemDB.ExecCmd "Insert Into LendbookBids Values(?,?,?,?,?)", R("rate"), R("amount"), R("period"), R("timestamp"), R("frr")
Next
MemDB.Exec "Delete From LendbookAsks"
For Each R In Result("asks")
MemDB.ExecCmd "Insert Into LendbookAsks Values(?,?,?,?,?)", R("rate"), R("amount"), R("period"), R("timestamp"), R("frr")
Next
Else
Debug.Print httpStatusText
End If
The Orderbook-query comes with only 3 instead 5 members in "bids" and "asks" - but the loops should be done in the same way
(e.g. using OrderBids and OrderAsks as the table-names).
Olaf
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|