Binance API interface - Excel VBA - excel

I'm trying to setup a API connector with my Binance account and have come across the below code (which I found here: https://github.com/krijnsent/crypto_vba/blob/master/ModExchBinance.bas) which I can't seem to tweak to provide the information I need (for one, the WebRequestURL() function isn't something I'm even familiar with)... Basically what I need is to be pointed in the right direction for some sample code.
Has anyone gone though this to fully automate the API whereby buy/sells are triggered in certain conditions and, if not, even parse the information (volume, open, High, Low, Close etc.) on 5 minute candles and it can prompt me to place the trades manually.
Code I have:
Sub TestBinance()
'Source: https://github.com/krijnsent/crypto_vba
'Remember to create a new API key for excel/VBA
Dim apikey As String
Dim secretkey As String
apikey = "your api key here"
secretkey = "your secret key here"
'Remove these 2 lines, unless you define 2 constants somewhere ( Public Const secretkey_btce = "the key to use everywhere" etc )
apikey = apikey_binance
secretkey = secretkey_binance
Debug.Print PublicBinance("time", "")
'{"serverTime":1513605418615}
Debug.Print PublicBinance("ticker/24hr", "?symbol=ETHBTC")
'{"symbol":"ETHBTC","priceChange":"0.00231500","priceChangePercent":"6.345","weightedAvgPrice":"0.03788715","prevClosePrice":"0.03648400","lastPrice":"0.03880200","lastQty":"0.29800000","bidPrice":"0.03873300","bidQty":"10.00000000","askPrice":"0.03883100","askQty":"17.18000000","openPrice":"0.03648700","highPrice":"0.04000000","lowPrice":"0.03631200","volume":"274355.20000000","quoteVolume":"10394.53526717","openTime":1513522564335,"closeTime":1513608964335,"firstId":7427497,"lastId":7702400,"count":274904}
Debug.Print GetBinanceTime()
'e.g. 1516565004894
'Unix time period:
t1 = DateToUnixTime("1/1/2014")
t2 = DateToUnixTime("1/1/2018")
Debug.Print PrivateBinance("account", apikey, secretkey)
'{"makerCommission":10,"takerCommission":10,"buyerCommission":0,"sellerCommission":0,"canTra etc...
Debug.Print PrivateBinance("order/test", apikey, secretkey, "symbol=LTCBTC&side=BUY&type=LIMIT&price=0.01&quantity=1&timeInForce=GTC")
'{} -> test orders return empty JSON
End Sub
Function PublicBinance(Method As String, Optional MethodOptions As String) As String
'https://binance.com/home/api
Dim Url As String
PublicApiSite = "https://api.binance.com"
urlPath = "/api/v1/" & Method & MethodOptions
Url = PublicApiSite & urlPath
PublicBinance = WebRequestURL(Url, "GET")
End Function
Function PrivateBinance(Method As String, apikey As String, secretkey As String, Optional MethodOptions As String) As String
Dim NonceUnique As String
Dim TimeCorrection As Long
'https://binance.com/home/api
'Get a 13-digit Nonce -> use the GetBinanceTime() to avoid a time correction
NonceUnique = GetBinanceTime() + 1000
TradeApiSite = "https://api.binance.com/api/v3/"
postdata = MethodOptions & "&timestamp=" & NonceUnique
APIsign = ComputeHash_C("SHA256", postdata, secretkey, "STRHEX")
Url = TradeApiSite & Method & "?" & postdata & "&signature=" & APIsign
'Binance requires a POST for orders, other commands are GETs
If InStr(Method, "order") > 0 Then
HTTPMethod = "POST"
Else
HTTPMethod = "GET"
End If
' Instantiate a WinHttpRequest object and open it
Set objHTTP = CreateObject("WinHttp.WinHttpRequest.5.1")
objHTTP.Open HTTPMethod, Url, False
objHTTP.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
objHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
objHTTP.setRequestHeader "X-MBX-APIKEY", apikey
objHTTP.Send get_url
objHTTP.WaitForResponse
PrivateBinance = objHTTP.ResponseText
Set objHTTP = Nothing
End Function
Function GetBinanceTime() As Double
Dim JsonResponse As String
Dim Json As Object
'PublicBinance time
JsonResponse = PublicBinance("time", "")
Set Json = JsonConverter.ParseJson(JsonResponse)
GetBinanceTime = Json("serverTime")
Set Json = Nothing
End Function

Related

API Loop through vba excel

I'm very new to API coding but I have created an API Code that inputs pressure and outputs temperature for a specific refrigerant on a website. However, I can only call for one refrigerant at a time, I was wondering if it is possible to create a string with all the refrigerant id (refId) numbers, so the API code could run through all of them in one long run?
Option Explicit
Public Function GetPressureFromTemp(ByVal Temperature As Double) As Double
Dim body As String
body = "{""Temperature"":""" & Temperature & """,""refId"":""r13"",""temperatureUnit"":""fahrenheit"",""pressureUnit"":""psi"","
body = body & """pressureReferencePoint"":""gauge"","
body = body & """pressureCalculationPoint"":""bubble"",""gaugeType"":""dry"",""altitudeInMeter"":0}"
With CreateObject("MSXML2.XMLHTTP")
.Open "POST", "https://reftools.danfoss.com/api/ref-slider/Pressure?refId=r13", False
.setRequestHeader "content-type", "application/json; charset=utf-8"
.send body
GetPressureFromTemp = CDbl(.responseText)
End With
End Function
Public Sub test()
Dim n As Double
Dim a As Double
a = 4984
n = -150.8
Do Until n >= 74.93
n = n + 0.1
'Debug.Print GetPressureFromTemp(n)
Range("J" & a) = GetPressureFromTemp(n)
a = a + 1
Loop
End Sub
I'm not sure how to loop through each ref ID, however I have the whole list containing the refrigerant id

How to find and format an address from a cell using a VBA function and Google Places API?

To make sure an address is always formatted the same way (which I will use in another VBA Sub), I'm trying to use the Google Places API in combination with a created VBA function.
The query works in the browser but not from the created function.
The working API (temporary API-key added) with a random address: https://maps.googleapis.com/maps/api/place/findplacefromtext/json?fields=formatted_address%2Cname%2Crating%2Copening_hours%2Cgeometry&input=Coendersweg%202&inputtype=textquery&key=API_KEY
It gives "Formatted_Address" which I'd like to show up as the result of the function.
Example result of random address:
Coendersweg 2, 9722GE Groningen / [Streetname number, Zipcode City]
If it's possible to make resulting address have the zip code (9722 GE) formatted as "9722GE" and the country ", Nederland" not show up that would be even better.
VBA code I have so far:
Function FindAddress(address, APIKEY)
Dim strURL As String
strURL = "https://maps.googleapis.com/maps/api/place/findplacefromtext/" & _
"json?fields=formatted_address%2Cname%2Crating%2Copening_hours%2Cgeometry&input=" _
& address & "&inputtype=textquery&key=" & APIKEY
Set httpReq = CreateObject("MSXML2.XMLHTTP")
With httpReq
.Open "GET", strURL, False
.Send
End With
Dim Response As String
Response = httpReq.ResponseText
Dim parsed As Dictionary
Set parsed = JsonConverter.ParseJson(Response)
Dim FoundAddress As String
FoundAddress = (formatted_address)
FindAddress = FoundAddress
I've the "JsonConverter.bas" from https://github.com/VBA-tools/VBA-JSON as a module inside my VBA.
Most of the code is borrowed from the following YouTube video. I made some tweaks to work with Google Places API instead of Google Directions API:
https://www.youtube.com/watch?v=_P2lj4yHNu4.
Here's a method that will return the formatted_address field. You can return other fields if you prefer -- the modifications should be obvious.
Note that I used early binding, but you can use late binding if you prefer.
Run against your input, => Coendersweg 2, 9722 GE Groningen, Netherlands
Option Explicit
Function getAddress(S As String)
Const API As String = "key=YOUR_API_KEY"
Const sURL1 As String = "https://maps.googleapis.com/maps/api/place/findplacefromtext/json?fields=formatted_address"
Const sURL2 As String = "input="
Const sURL3 As String = "inputtype=textquery"
Dim sAddr As String
Dim sURL() As String
Dim sLocation As String
Dim xhrRequest As XMLHTTP60
Dim strJSON As String, JSON As Object
sAddr = Replace(S, " ", "%20")
'Many ways to create the URL to send
ReDim sURL(3)
sURL(0) = sURL1
sURL(1) = sURL2 & sAddr
sURL(2) = sURL3
sURL(3) = API
Set xhrRequest = New XMLHTTP60
With xhrRequest
.Open "Get", Join(sURL, "&"), False
.Send
strJSON = .ResponseText
End With
Set JSON = ParseJson(strJSON)
If Not JSON("status") = "OK" Then
MsgBox "Status message: " & JSON("status")
Exit Function
End If
'might need to check if more than one candidate is returned
getAddress = JSON("candidates")(1)("formatted_address")
End Function
If you want to have the format different from what is shown, I suggest you use the Places api to return the place_id. You can then feed that value into the Place Details to return the address_components and format the address however you prefer.

Not able to send JSON data using a PUT API request with VBA Macros

I'm trying to send some data in JSON format to a server using VBA Macros. I'm using a PUT request to do the same (since this is the only method accepted by the server). However, I get an error that states - {"timestamp":1642010449580,"status":500,"error":"Internal Server Error","message":"java.lang.String cannot be cast to ...}.
The JSON data sample and the code are as below. I'm pretty new to APIs, any help on this issue is much appreciated.
JSON data format sample -
[{"Id":"PXX Global012","firstName":"Zoe","lastName":"Hunt","employeeStatus":"","countryCode":"UA","businessunitCode":"PBBCA1234"}, {"Id":"PXX Global012","firstName":"Julie","lastName":"Stan","employeeStatus":"","countryCode":"UA","businessunitCode":"PBBCA5253"}]
Code Used -
Sub PostJSONData()
Dim req As New WinHttpRequest
Dim myUrl As String, userName As String, Password As String, result As String, method As String
myUrl = Configuration.Range("AB2").value
userName = Configuration.Range("AB5").value
Password = Configuration.Range("AB6").value
req.Open "PUT", myUrl, False
req.setRequestHeader "Content-Type", "application/json"
req.SetCredentials userName, Password, HTTPREQUEST_SETCREDENTIALS_FOR_SERVER
req.send ExcelToJSON 'has the JSON data
result = req.responseText
If req.status <> 200 Then
MsgBox req.status & " - Error was found while sending the request", vbCritical, "Error while sending API Request"
Configuration.Range("AD2").value = result
statusCell.value = req.status
End If
End Sub
I've figured out the issue, looks like a base64 encoding is necessary to send credentials. I've used a function to do the encoding and made some modifications to my original code.
Sub PostJSONDatawithEncode()
Dim req As New WinHttpRequest
Dim myUrl As String, userName As String, Password As String, result As String, method As String
myUrl = Configuration.Range("AB2").value
userName = Configuration.Range("AB5").value
Password = Configuration.Range("AB6").value
method = Configuration.Range("AB4").value
req.Open method, myUrl, False
req.setRequestHeader "Content-Type", "application/json"
req.setRequestHeader "Accept", "application/json"
req.setRequestHeader "Authorization", "Basic " + EncodeBase64(userName + ":" + Password)
req.send ExcelToJSON
result = req.responseText
Configuration.Range("AD2").value = result
statusCell.value = req.status
If req.status <> 200 Then
' MsgBox req.status & " - Error was found while sending the request", vbCritical, "Error while sending API Request"
Configuration.Range("AD2").value = result
statusCell.value = req.status
End If
End Sub

Excel VBA Communicating with Jira using Isolated Site Minder cookies using REST

I have inherited an Excel Tracker sheet and the code originally was created by someone else who has since left the company.
We have an Excel VBA Tracker sheet which communicates with Jira and used to work fetching projects and issues without any issues until our company changed from site minder for cookies to "Isolated Site Minder" for more secure cookies, since the change over to the isolated site minder cookie authentication our Excel tracker sheet will fetch the project key from Jira without any problem but it brings the same list of 50 issues no matter which project we are querying Jira for and no matter how we change the code it wont see the issue "Key" and filter and fetch the correct issues for the project. I'm not brilliant as Excel VBA but I do understand and can follow what the code is doing and make small adjustments, but I have now inherited this tracker sheet and am not very good at the Jira code and communicating with each other
the code is as follows:
Public Function httpGet (ByVal url as String) As String()
Dim resultArray(2) as String 
Dim PostData as String
url = baseurl + url
Dim smiwhr As New SMIsolatedWinHttpRequest
With CreateObject("WinHTTP.WinHTTPrequest.5.1")
.Option(WinRequestOption_EnableRedirects) = True 
.Option(WinRequestOption_EnableHttpsToHttpRedirects) = True
smiwhr.NewRequest "GET", url
smiwhr.Send PostData
.Open "GET", url, False
.SetRequestHeader "Content-Type", "Application/json"
.SetRequestHeader "Accept", "application/json"
.SetRequestHeader "Cookie", sCookie
.Send
resultArray(0) = Status
resultArray(1) = .ResponseText
End With
httpGet = resultArray
End Function  
There is a function that gets the requests which has the code:
Public Function getRequestByPaging(ByVal projectKey as String, ByVal StartIndex as Integer, Optional maxResults As Integer, Optional fields As String) As Object
Dim resultArray() As String
Dim api as String
Dim jql As String
Dim PostData As String
api = "rest/api/2/search"
jql = "project=" & projectKey & " and issuetype!=\""Project\"" ORDER By Key ASC "
PostData = "{"
PostData = PostData + toJson ("jql", jql) + ","
PostData = PostData + toJson("StartAt", StartIndex) + ","
If maxResults <> "" Then
PostData = PostData + toArray("field", fields) + ","
End If
PostData = Mid(PostData, 1, Len(PostData) - 1)
PostData = Post + "}"
End Function  
The jql part does pick up the project key, it is when it sends the details of the project through to the Json that it returns the wrong issue key 
The Json function is as follows:
Public Function toJson (byVal As String, ByVal value As String) As String
If value = "" Then
toJson = """" + key + """ : null"
Else
toJson = """" + key + """ : """ + value + """"
End If
End Function
Any help would be very much appreciated
While editing your original question and adding syntax highlighting to it (otherwise your code cannot be read), I've noticed that the syntax in the function in question is probably wrong:
You had it:
If value = "" Then
toJson = """ + key + """ : null"
' ^^^ missing "
Else
toJson = """" + key + """ : """ + value """"
' ^ missing +
End If
It should be this way:
If value = "" Then
toJson = """" + key + """ : null"
Else
toJson = """" + key + """ : """ + value + """"
End If

Concatenate referenced URL into XML HTTP Request

The following snippet of code sends a XML request to the following site
Sub GetContents()
Dim XMLReq As New MSXML2.XMLHTTP60
XMLReq.Open "Get", "https://echa.europa.eu/brief-profile/-/briefprofile/100.028.723", False
XMLReq.send
End Sub
I have another Sub routine GetURL() which prints out the desired URL in this case: https://echa.europa.eu/brief-profile/-/briefprofile/100.028.723
How can I essentially concatenate the output of GetURL() into the BstrUrl? i.e.
XMLReq.Open "Get", "x", False where x is the output of GetURL()
Despite various attempts the syntax is not accepted as a URL.
Assuming you are combining from your earlier question then you need to ensure you write a function which returns the url (as Tim Williams has pointed out). I would expand upon this, in that I think you would need to consider adding a test to ensure both the request succeeded, there were results, and to pass the searchKeyWord as an argument to make your function more reusable. Along the same lines, you could pass the xmlhttp object into the function, so as to avoid continually creating and destroying them.
Avoid auto-instantiation, as you can get unexpected results, and Hungarian style notation. Personally, I also avoid those type characters, as they are harder to read.
vbNullString will offer faster assignment than = "".
I would also use a shorter, faster, and more reliable css pattern to retrieve the url, based on classes and a parent child relationship of two elements.
Public Sub GetContents()
Dim searchKeyWord As String, xmlReq As MSXML2.XMLHTTP60, html As MSHTML.HTMLDocument, url As String
searchKeyWord = "Acetone"
Set xmlReq = New MSXML2.XMLHTTP60
url = GetUrl(searchKeyWord, xmlReq)
Set html = New MSHTML.HTMLDocument
If url <> "N/A" Then
With xmlReq
.Open "GET", url, False
.send
If .Status = 200 Then
html.body.innerHTML = .responseText
Debug.Print html.querySelector("title").innerText
End If
End With
End If
End Sub
Public Function GetUrl(ByVal searchKeyWord As String, ByVal http As MSXML2.XMLHTTP60) As String
Const url = "https://echa.europa.eu/search-for-chemicals?p_auth=5ayUnMyz&p_p_id=disssimplesearch_WAR_disssearchportlet&p_p_lifecycle=1&p_p_state=normal&p_p_col_id=_118_INSTANCE_UFgbrDo05Elj__column-1&p_p_col_count=1&_disssimplesearch_WAR_disssearchportlet_javax.portlet.action=doSearchAction&_disssimplesearch_WAR_disssearchportlet_backURL=https%3A%2F%2Fecha.europa.eu%2Finformation-on-chemicals%3Fp_p_id%3Ddisssimplesearchhomepage_WAR_disssearchportlet%26p_p_lifecycle%3D0%26p_p_state%3Dnormal%26p_p_mode%3Dview%26p_p_col_id%3D_118_INSTANCE_UFgbrDo05Elj__column-1%26p_p_col_count%3D1%26_disssimplesearchhomepage_WAR_disssearchportlet_sessionCriteriaId%3D"
Dim html As MSHTML.HTMLDocument, dict As Object, i As Long, r As Long
Dim dictKey As Variant, payload$, ws As Worksheet
Set html = New MSHTML.HTMLDocument
Set dict = CreateObject("Scripting.Dictionary")
Set ws = ThisWorkbook.Worksheets("Sheet1")
dict("_disssimplesearchhomepage_WAR_disssearchportlet_formDate") = "1621017052777" 'timestamp
dict("_disssimplesearch_WAR_disssearchportlet_searchOccurred") = "true"
dict("_disssimplesearch_WAR_disssearchportlet_sskeywordKey") = searchKeyWord
dict("_disssimplesearchhomepage_WAR_disssearchportlet_disclaimer") = "true"
dict("_disssimplesearchhomepage_WAR_disssearchportlet_disclaimerCheckbox") = "on"
payload = vbNullString
For Each dictKey In dict
payload = IIf(Len(dictKey) = 0, WorksheetFunction.EncodeURL(dictKey) & "=" & WorksheetFunction.EncodeURL(dict(dictKey)), _
payload & "&" & WorksheetFunction.EncodeURL(dictKey) & "=" & WorksheetFunction.EncodeURL(dict(dictKey)))
Next dictKey
With http
.Open "POST", url, False
.setRequestHeader "User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36"
.setRequestHeader "Content-type", "application/x-www-form-urlencoded"
.send (payload)
If .Status = 200 Then
html.body.innerHTML = .responseText
Else
GetUrl = "N/A"
Exit Function
End If
End With
Dim result As Boolean
result = html.querySelectorAll(".lfr-search-container .substanceNameLink").Length > 0
GetUrl = IIf(result, html.querySelector(".lfr-search-container .substanceNameLink").href, "N/A")
End Function
If GetURL is a function returning a string then this should work:
Sub GetContents()
Dim XMLReq As New MSXML2.XMLHTTP60
Dim url
url = GetURL()
XMLReq.Open "Get", url, False
XMLReq.send
End Sub

Resources