andybiochem Posted October 2, 2021 Share Posted October 2, 2021 (edited) Hi All, Firstly, I accept no responsibility for how you use the following UDF, use at your own risk! Below is a very basic UDF that will allow communication with Binance's API (binance.com, not the US version). There is no error handling - add this yourself if you are concerned. If you are going to use this UDF in any meaningful way, carefully check the return of every single call, to make sure there is no error in the data you are receiving back from Binance. e.g. if you are pulling ticker prices, and suddenly you get $NULL returned, this could affect how you go on to place orders etc. I have very intentionally not provided an example of how to place orders using the UDF. If you are technically minded enough to use the UDF and understand how to construct the POST data, this should not be an issue. If you are struggling to work out how to place orders with this, please stop - no good can come from not fully understanding Binance's API and trying to automate it. In any event, please start with POSTing to "/api/v3/order/test" before commiting to your live account! The whole UDF calls directly on winhttp.dll, this was the only method I could find that gave a decent reliability, TCP / INET functions I found quite unreliable. Every UDF return gives you the HTTP Code and API Weight pulled out of the http header. Monitor these carefully if you're making heavy/lots of calls to the API; it's very easy to make a mistake and spam Binance's server, which will lead in a ban. Lastly, if you get "Timestamp for this request is outside of the recvwindow" errors back from Binance, it is because your computer clock is not synced with an NTP properly. Sync your clock, and the error should go away, try rebooting too - BUT, the error will probably return after a few days/weeks as the sync drops. Monitor for this error, and keep on top of it if you can! expandcollapse popup;----- API Keys ----- Global $sAPI_Key_Access = "enter your access key" Global $sAPI_Key_Secret = "enter your secret key" ;----- Prepare DLL ----- Global $hDll_WinHTTP = DllOpen("winhttp.dll") ;########## EXAMPLE API CALLS ########## ;----- Ping Binance ----- Global $sRet = _BINANCE_API_Call("api/v3/ping") ConsoleWrite($sRet & @CRLF & @CRLF) ;----- Get Binance's Server Time ----- $sRet = _BINANCE_API_Call("api/v3/time") ConsoleWrite($sRet & @CRLF & @CRLF) ;----- Get BTC/USDT Average Price ----- $sRet = _BINANCE_API_Call("api/v3/avgPrice","symbol=BTCUSDT") ConsoleWrite($sRet & @CRLF & @CRLF) ;----- Get ETH/BTC Live Ticker Price ----- For $i = 1 To 5 Sleep(100) $sRet = _BINANCE_API_Call("api/v3/ticker/price", "symbol=ETHBTC") ConsoleWrite($sRet & @CRLF) Next ConsoleWrite(@CRLF) ;----- Get Last 10 ETH/BTC Trades ----- $sRet = _BINANCE_API_Call("api/v3/trades", "symbol=ETHBTC&limit=10") ConsoleWrite($sRet & @CRLF & @CRLF) ;----- Get Your Account Data ----- $sRet = _BINANCE_API_Call("api/v3/account") ConsoleWrite($sRet & @CRLF & @CRLF) Func _BINANCE_API_Call($sEndPoint, $sParameters = "") ;************************************************** ; Performs Binance API Call Via Native WinHTTP dll ;************************************************** ;----- Vars ----- ; Presume GET, assign POST if needed in switch Local $sGETorPOST = "GET" ;----- Check Endpoint Required ----- ; Some endpoints require signing, other endpoints can be ; added as new cases. Switch $sEndPoint Case "api/v3/account" $sParameters &= "×tamp=" & _TimeStamp() $sParameters &= "&signature=" & _HMAC($sParameters, $sAPI_Key_Secret) Case "api/v3/order" $sGETorPOST = "POST" $sParameters &= "×tamp=" & _TimeStamp() $sParameters &= "&signature=" & _HMAC($sParameters, $sAPI_Key_Secret) Case "api/v3/myTrades" $sParameters &= "×tamp=" & _TimeStamp() $sParameters &= "&signature=" & _HMAC($sParameters, $sAPI_Key_Secret) EndSwitch ;----- Start Session ----- Local $hHTTP_Session = DllCall($hDll_WinHTTP, "handle", "WinHttpOpen", "wstr", "Mozilla/4.0", "dword", 0, "wstr", "", "wstr", "", "dword", 0)[0] ;----- Connect To Binance Server ----- Local $hHTTP_Connection = DllCall($hDll_WinHTTP, "handle", "WinHttpConnect", "handle", $hHTTP_Session, "wstr", "api.binance.com", "dword", 443, "dword", 0)[0] ;----- Prepare Request Data ----- If $sParameters <> "" Then $sParameters = "?" & $sParameters Local $hHTTP_Request = DllCall($hDll_WinHTTP, "handle", "WinHttpOpenRequest", "handle", $hHTTP_Connection, "wstr", $sGETorPOST, "wstr", $sEndPoint & $sParameters, "wstr", "HTTP/1.1", "wstr", "", "ptr", 0, "dword", 0x00800000)[0] ;----- Add Request Header ----- ; Adds API key to header even if not specifically needed, inconsequential DllCall($hDll_WinHTTP, "bool", "WinHttpAddRequestHeaders", "handle", $hHTTP_Request, "wstr", "X-MBX-APIKEY: " & $sAPI_Key_Access, "dword", -1, "dword", 0x10000000) ;----- Send Request To Server ----- DllCall($hDll_WinHTTP, "bool", "WinHttpSendRequest", "handle", $hHTTP_Request, "wstr", "", "dword", 0, "ptr", 0, "dword", 0, "dword", 0, "dword_ptr", 0) ;----- Recieve Response ----- DllCall($hDll_WinHTTP, "bool", "WinHttpReceiveResponse", "handle", $hHTTP_Request, "ptr", 0) ;----- Recieve Headers ----- ; Extract HTTP return code and API weight Local $sHeaders = DllCall($hDll_WinHTTP, "bool", "WinHttpQueryHeaders", "handle", $hHTTP_Request, "dword", 22, "wstr", "", "wstr", "", "dword*", 65536, "dword*", 0)[4] Local $sHTTP_ReturnCode = StringMid($sHeaders, StringInStr($sHeaders, "HTTP/1.1 ") + 9, StringInStr($sHeaders, @CR, 0, 1, StringInStr($sHeaders, "HTTP/1.1 ") + 9) - (StringInStr($sHeaders, "HTTP/1.1 ") + 9)) Local $sAPI_Weight = StringMid($sHeaders, StringInStr($sHeaders, "x-mbx-used-weight: ") + 19, StringInStr($sHeaders, @CR, 0, 1, StringInStr($sHeaders, "x-mbx-used-weight: ") + 19) - (StringInStr($sHeaders, "x-mbx-used-weight: ") + 19)) Local $sAPI_IPBan_RetryAfter_Sec = StringInStr($sHeaders, "Retry-After: ") = 0 ? "" : StringMid($sHeaders, StringInStr($sHeaders, "Retry-After: ") + 13, StringInStr($sHeaders, @CR, 0, 1, StringInStr($sHeaders, "Retry-After: ") + 13) - (StringInStr($sHeaders, "Retry-After: ") + 13)) ;----- Get Data ----- Local $sData = "" Local $iBytesToRead, $hBuffer_Data While 1 ;- Get Bytes To Read In This Loop - $iBytesToRead = DllCall($hDll_WinHTTP, "bool", "WinHttpQueryDataAvailable", "handle", $hHTTP_Request, "dword*", 0)[2] ;- Check If No More Data To Read - If $iBytesToRead <= 0 Then ExitLoop ;- Prep Data Buffer - $hBuffer_Data = DllStructCreate("char[" & $iBytesToRead & "]") ;- Read Data To Buffer - DllCall($hDll_WinHTTP, "bool", "WinHttpReadData", "handle", $hHTTP_Request, "struct*", $hBuffer_Data, "dword", $iBytesToRead, "dword*", 0) ;- Get Data From Buffer - $sData &= DllStructGetData($hBuffer_Data, 1) ;- Release - $hBuffer_Data = "" WEnd ;----- Close Handles ----- DllCall($hDll_WinHTTP, "bool", "WinHttpCloseHandle", "handle", $hHTTP_Request) DllCall($hDll_WinHTTP, "bool", "WinHttpCloseHandle", "handle", $hHTTP_Connection) DllCall($hDll_WinHTTP, "bool", "WinHttpCloseHandle", "handle", $hHTTP_Session) ;----- Return Data ----- ; Include HTTP Code and API Weight to check for overuse, and retry period if banned ; HTTP CODES : 429=over request limit, 418=IP banned due to overuse ; API WEIGHT : over 1200 will lead to ban Return '{"HTTPCode":"' & $sHTTP_ReturnCode & '","APIWeight":"' & $sAPI_Weight & ($sAPI_IPBan_RetryAfter_Sec = "" ? "" : '","Retry-After":"' & $sAPI_IPBan_RetryAfter_Sec) & '"}' & $sData EndFunc ;==>_BINANCE_API_Call Func _HMAC($bData, $bKey) ;************************************************** ; Create HMAC SHA256 Signature ;************************************************** Local $oHMAC = ObjCreate("System.Security.Cryptography.HMAC" & "SHA256") $oHMAC.key = Binary($bKey) Local $bHash = $oHMAC.ComputeHash_2(Binary($bData)) Return StringLower(StringMid($bHash, 3)) EndFunc ;==>_HMAC Func _TimeStamp() ;************************************************** ; Create UNIX-style TimeStamp ;************************************************** ; This is 'unix time', aka UTC time in milliseconds Local $aTimeStamp = DllCall("msvcrt.dll", "int:cdecl", "time", "int", 0) Return ($aTimeStamp[0] * 1000) + @MSEC ;convert to miliseconds EndFunc ;==>_TimeStamp An example return would be: {"HTTPCode":"200 OK","APIWeight":"4"}{"symbol":"ETHBTC","price":"0.07152900"} The first {} block is the HTTP code and API weight, the second {} block is the full Binance JSON reply. The JSON can be queried with a JSON UDF (do a search on the forum), or can be split with regexp. Again, please use with caution! Feel free to donate if you find this useful!: NANO nano_1161rm7egfzwgbtckwe8aoicee55897bbgc8apzrp1s3fzyyn7zqobbtkmfh Edited October 3, 2021 by andybiochem fraizor 1 - Table UDF - create simple data tables - Line Graph UDF GDI+ - quickly create simple line graphs with x and y axes (uses GDI+ with double buffer) - Line Graph UDF - quickly create simple line graphs with x and y axes (uses AI native graphic control) - Barcode Generator Code 128 B C - Create the 1/0 code for barcodes. - WebCam as BarCode Reader - use your webcam to read barcodes - Stereograms!!! - make your own stereograms in AutoIT - Ziggurat Gaussian Distribution RNG - generate random numbers based on normal/gaussian distribution - Box-Muller Gaussian Distribution RNG - generate random numbers based on normal/gaussian distribution - Elastic Radio Buttons - faux-gravity effects in AutoIT (from javascript)- Morse Code Generator - Generate morse code by tapping your spacebar! Link to comment Share on other sites More sharing options...
dersiniar Posted March 28, 2022 Share Posted March 28, 2022 I like this UDF, i use it to get live prices for my portfolio. Now id like to open and close trades, but i cqant figure out how to do it. Link to comment Share on other sites More sharing options...
fraizor Posted April 27 Share Posted April 27 On 10/3/2021 at 2:01 AM, andybiochem said: Hi All, Firstly, I accept no responsibility for how you use the following UDF, use at your own risk! Below is a very basic UDF that will allow communication with Binance's API (binance.com, not the US version). There is no error handling - add this yourself if you are concerned. If you are going to use this UDF in any meaningful way, carefully check the return of every single call, to make sure there is no error in the data you are receiving back from Binance. e.g. if you are pulling ticker prices, and suddenly you get $NULL returned, this could affect how you go on to place orders etc. I have very intentionally not provided an example of how to place orders using the UDF. If you are technically minded enough to use the UDF and understand how to construct the POST data, this should not be an issue. If you are struggling to work out how to place orders with this, please stop - no good can come from not fully understanding Binance's API and trying to automate it. In any event, please start with POSTing to "/api/v3/order/test" before commiting to your live account! The whole UDF calls directly on winhttp.dll, this was the only method I could find that gave a decent reliability, TCP / INET functions I found quite unreliable. Every UDF return gives you the HTTP Code and API Weight pulled out of the http header. Monitor these carefully if you're making heavy/lots of calls to the API; it's very easy to make a mistake and spam Binance's server, which will lead in a ban. Lastly, if you get "Timestamp for this request is outside of the recvwindow" errors back from Binance, it is because your computer clock is not synced with an NTP properly. Sync your clock, and the error should go away, try rebooting too - BUT, the error will probably return after a few days/weeks as the sync drops. Monitor for this error, and keep on top of it if you can! expandcollapse popup;----- API Keys ----- Global $sAPI_Key_Access = "enter your access key" Global $sAPI_Key_Secret = "enter your secret key" ;----- Prepare DLL ----- Global $hDll_WinHTTP = DllOpen("winhttp.dll") ;########## EXAMPLE API CALLS ########## ;----- Ping Binance ----- Global $sRet = _BINANCE_API_Call("api/v3/ping") ConsoleWrite($sRet & @CRLF & @CRLF) ;----- Get Binance's Server Time ----- $sRet = _BINANCE_API_Call("api/v3/time") ConsoleWrite($sRet & @CRLF & @CRLF) ;----- Get BTC/USDT Average Price ----- $sRet = _BINANCE_API_Call("api/v3/avgPrice","symbol=BTCUSDT") ConsoleWrite($sRet & @CRLF & @CRLF) ;----- Get ETH/BTC Live Ticker Price ----- For $i = 1 To 5 Sleep(100) $sRet = _BINANCE_API_Call("api/v3/ticker/price", "symbol=ETHBTC") ConsoleWrite($sRet & @CRLF) Next ConsoleWrite(@CRLF) ;----- Get Last 10 ETH/BTC Trades ----- $sRet = _BINANCE_API_Call("api/v3/trades", "symbol=ETHBTC&limit=10") ConsoleWrite($sRet & @CRLF & @CRLF) ;----- Get Your Account Data ----- $sRet = _BINANCE_API_Call("api/v3/account") ConsoleWrite($sRet & @CRLF & @CRLF) Func _BINANCE_API_Call($sEndPoint, $sParameters = "") ;************************************************** ; Performs Binance API Call Via Native WinHTTP dll ;************************************************** ;----- Vars ----- ; Presume GET, assign POST if needed in switch Local $sGETorPOST = "GET" ;----- Check Endpoint Required ----- ; Some endpoints require signing, other endpoints can be ; added as new cases. Switch $sEndPoint Case "api/v3/account" $sParameters &= "×tamp=" & _TimeStamp() $sParameters &= "&signature=" & _HMAC($sParameters, $sAPI_Key_Secret) Case "api/v3/order" $sGETorPOST = "POST" $sParameters &= "×tamp=" & _TimeStamp() $sParameters &= "&signature=" & _HMAC($sParameters, $sAPI_Key_Secret) Case "api/v3/myTrades" $sParameters &= "×tamp=" & _TimeStamp() $sParameters &= "&signature=" & _HMAC($sParameters, $sAPI_Key_Secret) EndSwitch ;----- Start Session ----- Local $hHTTP_Session = DllCall($hDll_WinHTTP, "handle", "WinHttpOpen", "wstr", "Mozilla/4.0", "dword", 0, "wstr", "", "wstr", "", "dword", 0)[0] ;----- Connect To Binance Server ----- Local $hHTTP_Connection = DllCall($hDll_WinHTTP, "handle", "WinHttpConnect", "handle", $hHTTP_Session, "wstr", "api.binance.com", "dword", 443, "dword", 0)[0] ;----- Prepare Request Data ----- If $sParameters <> "" Then $sParameters = "?" & $sParameters Local $hHTTP_Request = DllCall($hDll_WinHTTP, "handle", "WinHttpOpenRequest", "handle", $hHTTP_Connection, "wstr", $sGETorPOST, "wstr", $sEndPoint & $sParameters, "wstr", "HTTP/1.1", "wstr", "", "ptr", 0, "dword", 0x00800000)[0] ;----- Add Request Header ----- ; Adds API key to header even if not specifically needed, inconsequential DllCall($hDll_WinHTTP, "bool", "WinHttpAddRequestHeaders", "handle", $hHTTP_Request, "wstr", "X-MBX-APIKEY: " & $sAPI_Key_Access, "dword", -1, "dword", 0x10000000) ;----- Send Request To Server ----- DllCall($hDll_WinHTTP, "bool", "WinHttpSendRequest", "handle", $hHTTP_Request, "wstr", "", "dword", 0, "ptr", 0, "dword", 0, "dword", 0, "dword_ptr", 0) ;----- Recieve Response ----- DllCall($hDll_WinHTTP, "bool", "WinHttpReceiveResponse", "handle", $hHTTP_Request, "ptr", 0) ;----- Recieve Headers ----- ; Extract HTTP return code and API weight Local $sHeaders = DllCall($hDll_WinHTTP, "bool", "WinHttpQueryHeaders", "handle", $hHTTP_Request, "dword", 22, "wstr", "", "wstr", "", "dword*", 65536, "dword*", 0)[4] Local $sHTTP_ReturnCode = StringMid($sHeaders, StringInStr($sHeaders, "HTTP/1.1 ") + 9, StringInStr($sHeaders, @CR, 0, 1, StringInStr($sHeaders, "HTTP/1.1 ") + 9) - (StringInStr($sHeaders, "HTTP/1.1 ") + 9)) Local $sAPI_Weight = StringMid($sHeaders, StringInStr($sHeaders, "x-mbx-used-weight: ") + 19, StringInStr($sHeaders, @CR, 0, 1, StringInStr($sHeaders, "x-mbx-used-weight: ") + 19) - (StringInStr($sHeaders, "x-mbx-used-weight: ") + 19)) Local $sAPI_IPBan_RetryAfter_Sec = StringInStr($sHeaders, "Retry-After: ") = 0 ? "" : StringMid($sHeaders, StringInStr($sHeaders, "Retry-After: ") + 13, StringInStr($sHeaders, @CR, 0, 1, StringInStr($sHeaders, "Retry-After: ") + 13) - (StringInStr($sHeaders, "Retry-After: ") + 13)) ;----- Get Data ----- Local $sData = "" Local $iBytesToRead, $hBuffer_Data While 1 ;- Get Bytes To Read In This Loop - $iBytesToRead = DllCall($hDll_WinHTTP, "bool", "WinHttpQueryDataAvailable", "handle", $hHTTP_Request, "dword*", 0)[2] ;- Check If No More Data To Read - If $iBytesToRead <= 0 Then ExitLoop ;- Prep Data Buffer - $hBuffer_Data = DllStructCreate("char[" & $iBytesToRead & "]") ;- Read Data To Buffer - DllCall($hDll_WinHTTP, "bool", "WinHttpReadData", "handle", $hHTTP_Request, "struct*", $hBuffer_Data, "dword", $iBytesToRead, "dword*", 0) ;- Get Data From Buffer - $sData &= DllStructGetData($hBuffer_Data, 1) ;- Release - $hBuffer_Data = "" WEnd ;----- Close Handles ----- DllCall($hDll_WinHTTP, "bool", "WinHttpCloseHandle", "handle", $hHTTP_Request) DllCall($hDll_WinHTTP, "bool", "WinHttpCloseHandle", "handle", $hHTTP_Connection) DllCall($hDll_WinHTTP, "bool", "WinHttpCloseHandle", "handle", $hHTTP_Session) ;----- Return Data ----- ; Include HTTP Code and API Weight to check for overuse, and retry period if banned ; HTTP CODES : 429=over request limit, 418=IP banned due to overuse ; API WEIGHT : over 1200 will lead to ban Return '{"HTTPCode":"' & $sHTTP_ReturnCode & '","APIWeight":"' & $sAPI_Weight & ($sAPI_IPBan_RetryAfter_Sec = "" ? "" : '","Retry-After":"' & $sAPI_IPBan_RetryAfter_Sec) & '"}' & $sData EndFunc ;==>_BINANCE_API_Call Func _HMAC($bData, $bKey) ;************************************************** ; Create HMAC SHA256 Signature ;************************************************** Local $oHMAC = ObjCreate("System.Security.Cryptography.HMAC" & "SHA256") $oHMAC.key = Binary($bKey) Local $bHash = $oHMAC.ComputeHash_2(Binary($bData)) Return StringLower(StringMid($bHash, 3)) EndFunc ;==>_HMAC Func _TimeStamp() ;************************************************** ; Create UNIX-style TimeStamp ;************************************************** ; This is 'unix time', aka UTC time in milliseconds Local $aTimeStamp = DllCall("msvcrt.dll", "int:cdecl", "time", "int", 0) Return ($aTimeStamp[0] * 1000) + @MSEC ;convert to miliseconds EndFunc ;==>_TimeStamp An example return would be: {"HTTPCode":"200 OK","APIWeight":"4"}{"symbol":"ETHBTC","price":"0.07152900"} The first {} block is the HTTP code and API weight, the second {} block is the full Binance JSON reply. The JSON can be queried with a JSON UDF (do a search on the forum), or can be split with regexp. Again, please use with caution! Feel free to donate if you find this useful!: NANO nano_1161rm7egfzwgbtckwe8aoicee55897bbgc8apzrp1s3fzyyn7zqobbtkmfh Amazzing , you are a lifesaver , thank you very much for sharing this ... Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now