Q: Which headers should I fill?
A:
Content-type: application/json
Accept: application/json
Accept-encoding: gzip, deflate
Authorization: HMAC webApiId:webApiKey:unix_timestamp_in_ms:Base64HMACSignature
Q: How to perform HMAC authentication?
A:
Signature = unix_timestamp_in_ms + webApiId + webApiKey + req.getMethod() + req.getURI() + content;
Base64HMACSignature = Base64(HmacSHA256(Signature, webApiSecret));
Header = "Authorization: HMAC:webApiId:webApiKey:unix_timestamp_in_ms:Base64HMACSignature"
Example: Signature = "1509018187496b3a113e4-77d2-4118-941d-3168803612abRCsr8eCZsyR59emhGEThttps://localhost:8443/api/v1/account";
There is a sample JavaScript code:
long timestamp = new Date(System.currentTimeMillis()).getTime();
String signature = timestamp + _webApiId + _webApiKey + req.getMethod() + req.getURI() + _content;
byte[] messageBytes = signature.getBytes(StandardCharsets.US_ASCII);
byte[] hmacKeyByte = _webApiSecret.getBytes(StandardCharsets.US_ASCII);
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(hmacKeyByte, "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] mac_data = sha256_HMAC.doFinal(messageBytes);
byte[] valueDecoded = Base64.encodeBase64(mac_data);
String base64HMACStr = new String(valueDecoded);
req.setHeader(HttpHeaders.AUTHORIZATION, String.format("%1$s %2$s:%3$s:%4$s:%5$s", "HMAC ", _webApiId, _webApiKey, timestamp, base64HMACStr));
Q: How to use a Bearer access token?
A:
Authorization: Bearer v4.local...
Bearer tokens are short-lived (at most 300 seconds) reusable PASETO v4.local access
tokens issued by the server through the trusted backend Manager channel. One token
authorizes multiple requests until it expires. There is no refresh endpoint: request
a new independent token proactively before expiration, or after the first 401
response; all bearer tokens of an account share one server session, so a renewed
token continues it. A cryptographically valid token can still be rejected with 403 by
the current account policy (blocked account, access list restrictions, Web API disabled).
Q: How to download content using Curl, Wget, PowerShell?
A: All responses of the Web API is compressed using gzip stream.
You have to add "Accept: application/json" and "Accept-encoding: gzip, deflate"
headers to your request and use gunzip tool to decompress the stream.
Unix curl:
curl -v -H "Content-type: application/json" -H "Accept: application/json" -H "Accept-encoding: gzip, deflate" apimethod | gunzip -
Unix wget:
wget -S -q --header "Content-type: application/json" --header "Accept: application/json" --header "Accept-encoding: gzip, deflate" -O - apimethod | gunzip -
Windows PowerShell:
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Content-type","application/json")
$headers.Add("Accept","application/json")
$headers.Add("Accept-Encoding","gzip")
Invoke-RestMethod -Method Get 'apimethod' -Headers $headers
Add-Type -AssemblyName System.Web;
Add-Type -AssemblyName System.Net.Http;
Add-Type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
class WebClient {
[string] $Id
[string] $Key
[string] $Secret
[string] $BaseAddress
[System.Net.Http.HttpClient] $client
WebClient([string] $baseAddress, [string] $id, [string] $key, [string] $secret){
$this.Id = $id
$this.Key = $key
$this.Secret = $secret
$this.BaseAddress = $baseAddress
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
[System.Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Ssl3 -bor [Net.SecurityProtocolType]::Tls12
$handler = [System.Net.Http.HttpClientHandler]::new()
$handler.AutomaticDecompression = [System.Net.DecompressionMethods]::Gzip -bor [System.Net.DecompressionMethods]::Deflate
$this.client = [System.Net.Http.HttpClient]::new($handler)
$this.client.DefaultRequestHeaders.Accept.Clear()
$this.client.DefaultRequestHeaders.Accept.Add([System.Net.Http.Headers.MediaTypeWithQualityHeaderValue]::new("application/json"))
}
[long] DateTimeToTimestamp([DateTime] $time) {
return [long]($time - [DateTime]::new(1970, 1, 1, 0, 0, 0, 0, [DateTimeKind]::Utc)).TotalMilliseconds
}
[void] ExecuteGetRequest([string] $uri, [string] $outputfile){
$request = [System.Net.Http.HttpRequestMessage]::new()
$request.RequestUri = $this.BaseAddress + $uri
$request.Method = [System.Net.Http.HttpMethod]::Get
$timestamp = $this.DateTimeToTimestamp([DateTime]::UtcNow)
if ($request.Content -eq $null) {
$content = ""
}
else {
$content = $request.Content.ReadAsString()
}
$signature = $timestamp.ToString() + $this.Id + $this.Key + $request.Method.Method + $request.RequestUri + $content
$hash = $this.CalculateHmacWithSha256($signature)
$request.Headers.Authorization = [System.Net.Http.Headers.AuthenticationHeaderValue]::new("HMAC", $this.Id+':'+$this.Key+':'+$timestamp+':'+$hash)
try {
$response = $this.client.SendAsync($request).GetAwaiter().GetResult()
if ($response.IsSuccessStatusCode){
$fileStream = [System.IO.FileStream]::new($outputfile,[System.IO.FileMode]::Create)
$response.Content.CopyToAsync($fileStream).GetAwaiter().GetResult()
$fileStream.Dispose()
}
else {
Write-Host 'An error has occurred:'
Write-Host $response
}
}
catch{
Write-Host $_.Exception
}
}
[string] CalculateHmacWithSha256 ([string] $signature)
{
$encoding = [System.Text.ASCIIEncoding]::new()
$encodedSecret = $encoding.GetBytes($this.Secret)
$hmacsha = [System.Security.Cryptography.HMACSHA256]::new($encodedSecret)
try {
$message = $encoding.GetBytes($signature)
$hashBytes = $hmacsha.ComputeHash($message)
$hash = [Convert]::ToBase64String($hashBytes)
return $hash;
}
finally{
$hmacsha.Dispose();
}
}
[void] DownloadBarsInfo([string] $symbol,[string] $periodicity,[string] $priceType,[string] $outputfile) {
$uri = '/api/v2/quotehistory/download/bars/info/'+[System.Web.HttpUtility]::UrlPathEncode($symbol)+'/'+$periodicity+'/'+$priceType;
$this.ExecuteGetRequest($uri, $outputfile);
<# .DESCRIPTION
Download bars info file.
.PARAMETER symbol
Specifies symbol
.PARAMETER periodicity
Specifies bar periodicity (Supports only M1, H1)
.PARAMETER priceType
Specifies bar price type (Ask, Bid)
.EXAMPLE
PS>
DownloadBarsInfo('BTCUSD', 'M1', 'Bid', 'C:\BTCUSD_M1_Bid_info.zip');
#>
}
[void] DownloadBars([string] $symbol,[string] $periodicity,[string] $priceType,[DateTime] $time, [string] $outputfile) {
$uri = '/api/v2/quotehistory/download/bars/'+[System.Web.HttpUtility]::UrlPathEncode($symbol)+'/'+$periodicity+'/'+$priceType+'/'+$this.DateTimeToTimestamp($time)
$this.ExecuteGetRequest($uri, $outputfile);
<# .DESCRIPTION
Download bars info file.
.PARAMETER symbol
Specifies symbol
.PARAMETER periodicity
Specifies bar periodicity (Supports only M1, H1)
.PARAMETER priceType
Specifies bar price type (Ask, Bid)
.PARAMETER time
Specifies file timestamp
.EXAMPLE
PS>
DownloadBars('BTCUSD', 'M1', 'Bid', [DateTime]::new(2019,12,1), 'C:\BTCUSD_M1_Bid.zip');
#>
}
}
$symbol = 'TTT_QUOTESYMBOL';
$id = 'e32511f4-7f49-43b2-b6b4-aaa3563799cc';
$key = 'kxNdnWycKCFEERP7';
$secret = 'y2Q9CJgRx3KWQ9kYg7qRNM6hTSPYMyhBZfA7yBb2GYW4GH7fhxCnpQ3W6GpT5sd8';
$outputfile = 'D:\!\outinfo.zip';
$outputfile1 = 'D:\!\out.zip';
Clear-Host
$webClient = [WebClient]::new('https://localhost:8443', $id, $key, $secret);
$webClient.DownloadBarsInfo($symbol, 'M1', 'Bid', $outputfile);
$webClient.DownloadBars($symbol, 'M1', 'Bid', [DateTime]::new(2019,12,1), $outputfile1);