diff --git a/nuxhash/nhrest/.gitignore b/nuxhash/nhrest/.gitignore new file mode 100644 index 0000000..b23f9a5 --- /dev/null +++ b/nuxhash/nhrest/.gitignore @@ -0,0 +1,2 @@ +.idea +javascript/node_modules diff --git a/nuxhash/nhrest/README.md b/nuxhash/nhrest/README.md new file mode 100644 index 0000000..5c10794 --- /dev/null +++ b/nuxhash/nhrest/README.md @@ -0,0 +1,21 @@ +# rest-clients-demo + +### TEST environment + +Generate Api key and Secret for test platform on: + +https://test.nicehash.com (User / Settings / API Keys) +Organization ID is displayed just above "+ Create new API key" button. + +Use https://api-test.nicehash.com for API domain. + +The entire platform runs on testnet. This means that you don’t have to use your own funds to test the platform. This is the opportunity to familiarize yourself with the new system, place hash-power orders and try trading without spending any real money. + +![](https://raw.githubusercontent.com/nicehash/rest-clients-demo/master/generate_key.gif) + +### PRODUCTION environment + +To use production just generate key the same way on https://www.nicehash.com and use https://api2.nicehash.com for API domain. + +### API docs +Can be found here: https://docs.nicehash.com/ diff --git a/nuxhash/nhrest/bash/README.md b/nuxhash/nhrest/bash/README.md new file mode 100644 index 0000000..a565ff7 --- /dev/null +++ b/nuxhash/nhrest/bash/README.md @@ -0,0 +1,17 @@ +# Instructions + +Get python client + + wget https://raw.githubusercontent.com/nicehash/rest-clients-demo/master/python/nicehash.py + +Install dependencies + + pip install requests + +Enter API key/secret/org in to the bash script + + ./run.sh + +For more options see + + python nicehash.py -h diff --git a/nuxhash/nhrest/bash/run.sh b/nuxhash/nhrest/bash/run.sh new file mode 100644 index 0000000..efb71c2 --- /dev/null +++ b/nuxhash/nhrest/bash/run.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# Configuration +ORG="---" +KEY="---" +SEC="---" +#API="https://api2.nicehash.com" #prod env +API="https://api-test.nicehash.com" # test env + +# Command +NHCLIENT="python nicehash.py -b $API -o $ORG -k $KEY -s $SEC" + +# Run method +eval "$NHCLIENT -m GET -p '/main/api/v2/accounting/accounts'"; # -b '{json}' diff --git a/nuxhash/nhrest/c#/connect/connect.sln b/nuxhash/nhrest/c#/connect/connect.sln new file mode 100644 index 0000000..d685682 --- /dev/null +++ b/nuxhash/nhrest/c#/connect/connect.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29021.104 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "connect", "connect\connect.csproj", "{25EF6083-E791-4BAD-A0C0-462A1A1220E3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {25EF6083-E791-4BAD-A0C0-462A1A1220E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {25EF6083-E791-4BAD-A0C0-462A1A1220E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {25EF6083-E791-4BAD-A0C0-462A1A1220E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {25EF6083-E791-4BAD-A0C0-462A1A1220E3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A8EDF606-C147-427F-B08D-FECCD44EC071} + EndGlobalSection +EndGlobal diff --git a/nuxhash/nhrest/c#/connect/connect/Api.cs b/nuxhash/nhrest/c#/connect/connect/Api.cs new file mode 100644 index 0000000..af40e3d --- /dev/null +++ b/nuxhash/nhrest/c#/connect/connect/Api.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace connect +{ + class Api + { + private string urlRoot; + private string orgId; + private string apiKey; + private string apiSecret; + + public Api(string urlRoot, string orgId, string apiKey, string apiSecret) + { + this.urlRoot = urlRoot; + this.orgId = orgId; + this.apiKey = apiKey; + this.apiSecret = apiSecret; + } + + private static string HashBySegments(string key, string apiKey, string time, string nonce, string orgId, string method, string encodedPath, string query, string bodyStr) + { + List segments = new List(); + segments.Add(apiKey); + segments.Add(time); + segments.Add(nonce); + segments.Add(null); + segments.Add(orgId); + segments.Add(null); + segments.Add(method); + segments.Add(encodedPath == null ? null : encodedPath); + segments.Add(query == null ? null : query); + + if (bodyStr != null && bodyStr.Length > 0) { + segments.Add(bodyStr); + } + return Api.CalcHMACSHA256Hash(Api.JoinSegments(segments), key); + } + private static string getPath(string url) + { + var arrSplit = url.Split('?'); + return arrSplit[0]; + } + private static string getQuery(string url) { + var arrSplit = url.Split('?'); + + if (arrSplit.Length == 1) + { + return null; + } + else + { + return arrSplit[1]; + } + } + + private static string JoinSegments(List segments) { + var sb = new System.Text.StringBuilder(); + bool first = true; + foreach (var segment in segments) { + if (!first) + { + sb.Append("\x00"); + } + else + { + first = false; + } + + if (segment != null) + { + sb.Append(segment); + } + } + //Console.WriteLine("["+sb.ToString()+"]"); + return sb.ToString(); + } + + private static string CalcHMACSHA256Hash(string plaintext, string salt) + { + string result = ""; + var enc = Encoding.Default; + byte[] + baText2BeHashed = enc.GetBytes(plaintext), + baSalt = enc.GetBytes(salt); + System.Security.Cryptography.HMACSHA256 hasher = new System.Security.Cryptography.HMACSHA256(baSalt); + byte[] baHashedText = hasher.ComputeHash(baText2BeHashed); + result = string.Join("", baHashedText.ToList().Select(b => b.ToString("x2")).ToArray()); + return result; + } + + public string get(string url) + { + return this.get(url, false, null); + } + + public string get(string url, bool auth, string time) + { + var client = new RestSharp.RestClient(this.urlRoot); + var request = new RestSharp.RestRequest(url); + + if (auth) + { + string nonce = Guid.NewGuid().ToString(); + string digest = Api.HashBySegments(this.apiSecret, this.apiKey, time, nonce, this.orgId, "GET", getPath(url), getQuery(url), null); + + request.AddHeader("X-Time", time); + request.AddHeader("X-Nonce", nonce); + request.AddHeader("X-Auth", this.apiKey + ":" + digest); + request.AddHeader("X-Organization-Id", this.orgId); + } + + var response = client.Execute(request, RestSharp.Method.GET); + var content = response.Content; + return content; + } + + public string post(string url, string payload, string time, bool requestId) + { + var client = new RestSharp.RestClient(this.urlRoot); + var request = new RestSharp.RestRequest(url); + request.AddHeader("Accept", "application/json"); + request.AddHeader("Content-type", "application/json"); + + string nonce = Guid.NewGuid().ToString(); + string digest = Api.HashBySegments(this.apiSecret, this.apiKey, time, nonce, this.orgId, "POST", getPath(url), getQuery(url), payload); + + if (payload !=null) + { + request.AddJsonBody(payload); + } + + request.AddHeader("X-Time", time); + request.AddHeader("X-Nonce", nonce); + request.AddHeader("X-Auth", this.apiKey + ":" + digest); + request.AddHeader("X-Organization-Id", this.orgId); + + if (requestId) + { + request.AddHeader("X-Request-Id", Guid.NewGuid().ToString()); + } + + var response = client.Execute(request, RestSharp.Method.POST); + var content = response.Content; + return content; + } + + public string delete(string url, string time, bool requestId) + { + var client = new RestSharp.RestClient(this.urlRoot); + var request = new RestSharp.RestRequest(url); + + string nonce = Guid.NewGuid().ToString(); + string digest = Api.HashBySegments(this.apiSecret, this.apiKey, time, nonce, this.orgId, "DELETE", getPath(url), getQuery(url), null); + + request.AddHeader("X-Time", time); + request.AddHeader("X-Nonce", nonce); + request.AddHeader("X-Auth", this.apiKey + ":" + digest); + request.AddHeader("X-Organization-Id", this.orgId); + + if (requestId) + { + request.AddHeader("X-Request-Id", Guid.NewGuid().ToString()); + } + + var response = client.Execute(request, RestSharp.Method.DELETE); + var content = response.Content; + return content; + } + } +} diff --git a/nuxhash/nhrest/c#/connect/connect/App.config b/nuxhash/nhrest/c#/connect/connect/App.config new file mode 100644 index 0000000..56efbc7 --- /dev/null +++ b/nuxhash/nhrest/c#/connect/connect/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/nuxhash/nhrest/c#/connect/connect/Connect.cs b/nuxhash/nhrest/c#/connect/connect/Connect.cs new file mode 100644 index 0000000..5bd76f1 --- /dev/null +++ b/nuxhash/nhrest/c#/connect/connect/Connect.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace connect +{ + class Connect + { + static void Main(string[] args) + { + Console.WriteLine("running HashPowerOrder"); + new Hpo(); + Console.WriteLine("\n\nrunning Exchange"); + new Exch(); + Console.ReadLine(); + } + } + + public class ServerTime + { + public string serverTime { get; set; } + } + public class Pool + { + public string id { get; set; } + } + public class Order + { + public string id { get; set; } + } + public class OrderBooks + { + public List sell { get; set; } + public List buy { get; set; } + } +} diff --git a/nuxhash/nhrest/c#/connect/connect/Exch.cs b/nuxhash/nhrest/c#/connect/connect/Exch.cs new file mode 100644 index 0000000..12a0921 --- /dev/null +++ b/nuxhash/nhrest/c#/connect/connect/Exch.cs @@ -0,0 +1,84 @@ +using NLog; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace connect +{ + class Exch + { + private static NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); + + private static string URL_ROOT = "https://api-test.nicehash.com"; //use https://api2.nicehash.com for production + private static string ORG_ID = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"; + private static string API_KEY = "ffffffff-gggg-hhhh-iiii-jjjjjjjjjjjj"; + private static string API_SECRET = "kkkkkkkk-llll-mmmm-nnnn-oooooooooooooooooooo-pppp-qqqq-rrrr-ssssssssssss"; + + private static string CURRENCY_SELL = "TBTC"; //user BTC for production + private static string CURRENCY_BUY = "TLTC"; //use LTC for production + + public Exch() + { + var config = new NLog.Config.LoggingConfiguration(); + var logconsole = new NLog.Targets.ConsoleTarget("logconsole"); + config.AddRule(LogLevel.Info, LogLevel.Fatal, logconsole); + NLog.LogManager.Configuration = config; + + Api api = new Api(URL_ROOT, ORG_ID, API_KEY, API_SECRET); + + //get server time + string timeResponse = api.get("/api/v2/time"); + ServerTime serverTimeObject = Newtonsoft.Json.JsonConvert.DeserializeObject(timeResponse); + string time = serverTimeObject.serverTime; + Logger.Info("server time: {}", time); + + //get algo settings + string exchResponse = api.get("/exchange/api/v2/info/status"); + Console.WriteLine("[[["+exchResponse+"]]]"); + DataTable exchArray = Newtonsoft.Json.JsonConvert.DeserializeObject(exchResponse); + + DataRow mySettings = null; + foreach (DataRow symbol in exchArray.Rows) + { + if (symbol["baseAsset"].Equals(CURRENCY_BUY)) + { + mySettings = symbol; + } + } + Logger.Info("exchange settings: {}", mySettings["currency"]); + + //get balance + string accountsResponse = api.get("/main/api/v2/accounting/accounts", true, time); + DataTable accountsArray = Newtonsoft.Json.JsonConvert.DeserializeObject(accountsResponse); + + DataRow myBalace = null; + foreach (DataRow account in accountsArray.Rows) + { + if (account["currency"].Equals(CURRENCY_SELL)) + { + myBalace = account; + } + } + Logger.Info("balance: {} {}", myBalace["balance"], CURRENCY_SELL); + + //get order book + string orderBookResponse = api.get("/exchange/api/v2/orderbook?market=" + CURRENCY_BUY + CURRENCY_SELL + "&limit=100", true, time); + OrderBooks orderBooks = Newtonsoft.Json.JsonConvert.DeserializeObject(orderBookResponse); + Logger.Info("cheapest offer price: {} supply: {}", orderBooks.sell[0][0], orderBooks.sell[0][1]); + + double qty = 0.1 * 2; + string sQty = qty.ToString("0.00000000", System.Globalization.CultureInfo.InvariantCulture); + string sPrice = orderBooks.sell[0][0].ToString("0.00000000", System.Globalization.CultureInfo.InvariantCulture); + + //buy with limit order + string url = "/exchange/api/v2/order?market=" + CURRENCY_BUY + CURRENCY_SELL + "&side=buy&type=limit&quantity=" + sQty + "&price=" + sPrice; + Logger.Info("order url: {}", url); + string orderCreateResponse = api.post(url, null, time, true); + Logger.Info("order create: {}", orderCreateResponse); + } + } + +} diff --git a/nuxhash/nhrest/c#/connect/connect/Hpo.cs b/nuxhash/nhrest/c#/connect/connect/Hpo.cs new file mode 100644 index 0000000..6e91d0d --- /dev/null +++ b/nuxhash/nhrest/c#/connect/connect/Hpo.cs @@ -0,0 +1,122 @@ +using NLog; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace connect +{ + class Hpo + { + private static NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); + + private static string URL_ROOT = "https://api-test.nicehash.com"; //use https://api2.nicehash.com for production + private static string ORG_ID = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"; + private static string API_KEY = "ffffffff-gggg-hhhh-iiii-jjjjjjjjjjjj"; + private static string API_SECRET = "kkkkkkkk-llll-mmmm-nnnn-oooooooooooooooooooo-pppp-qqqq-rrrr-ssssssssssss"; + + private static string ALGORITHM = "X16R"; //algo of your order + private static string CURRENCY = "TBTC"; //user BTC for production + + public Hpo() + { + var config = new NLog.Config.LoggingConfiguration(); + var logconsole = new NLog.Targets.ConsoleTarget("logconsole"); + config.AddRule(LogLevel.Info, LogLevel.Fatal, logconsole); + NLog.LogManager.Configuration = config; + + Api api = new Api(URL_ROOT, ORG_ID, API_KEY, API_SECRET); + + //get server time + string timeResponse = api.get("/api/v2/time"); + ServerTime serverTimeObject = Newtonsoft.Json.JsonConvert.DeserializeObject(timeResponse); + string time = serverTimeObject.serverTime; + Logger.Info("server time: {}", time); + + //get algo settings + string algosResponse = api.get("/main/api/v2/mining/algorithms"); + DataSet algoObject = Newtonsoft.Json.JsonConvert.DeserializeObject(algosResponse); + DataTable algoTable = algoObject.Tables["miningAlgorithms"]; + + DataRow mySettings = null; + foreach (DataRow algo in algoTable.Rows) + { + if (algo["algorithm"].Equals(ALGORITHM)) + { + mySettings = algo; + } + } + Logger.Info("algo settings: {}", mySettings["algorithm"]); + + //get balance + string accountsResponse = api.get("/main/api/v2/accounting/accounts", true, time); + DataTable accountsArray = Newtonsoft.Json.JsonConvert.DeserializeObject(accountsResponse); + + DataRow myBalace = null; + foreach (DataRow account in accountsArray.Rows) + { + if (account["currency"].Equals(CURRENCY)) + { + myBalace = account; + } + } + Logger.Info("balance: {} {}", myBalace["balance"], CURRENCY); + + //create pool + Dictionary pool = new Dictionary + { + { "algorithm", ALGORITHM }, + { "name", "my pool " + Guid.NewGuid().ToString() }, + { "username", "pool_username" }, //your pool username + { "password", "x" }, //your pool password + { "stratumHostname", "pool.host.name" }, //pool hostname + { "stratumPort", "3456" } //pool port + }; + + string poolResponse = api.post("/main/api/v2/pool", Newtonsoft.Json.JsonConvert.SerializeObject(pool), time, false); + Pool poolObject = Newtonsoft.Json.JsonConvert.DeserializeObject(poolResponse); + string myPoolId = poolObject.id; + Logger.Info("new pool id: {}", myPoolId); + + //create order + Dictionary order = new Dictionary { + { "algorithm", ALGORITHM }, + { "amount", (string)mySettings["minimalOrderAmount"] }, + { "displayMarketFactor", (string)mySettings["displayMarketFactor"] }, + { "limit", (string)mySettings["minSpeedLimit"] }, // GH [minSpeedLimit-maxSpeedLimit] || 0 - unlimited speed + { "market", "EU" }, + { "marketFactor", (string)mySettings["marketFactor"] }, + { "poolId", myPoolId }, + { "price", "0.0010" }, //per BTC/GH/day + { "type", "STANDARD" } + }; + + string newOrderResponse = api.post("/main/api/v2/hashpower/order", Newtonsoft.Json.JsonConvert.SerializeObject(order), time, true); + Order orderObject = Newtonsoft.Json.JsonConvert.DeserializeObject(newOrderResponse); + string myOrderId = orderObject.id; + Logger.Info("new order id: {}", myOrderId); + + //update price and limit + Dictionary updateOrder = new Dictionary { + { "displayMarketFactor", (string)mySettings["displayMarketFactor"] }, + { "limit", "0.11" }, // GH [minSpeedLimit-maxSpeedLimit] || 0 - unlimited speed + { "marketFactor", (string)mySettings["marketFactor"] }, + { "price", "0.00123" } //per BTC/GH/day + }; + + string updateOrderResponse = api.post("/main/api/v2/hashpower/order/" + myOrderId + "/updatePriceAndLimit", Newtonsoft.Json.JsonConvert.SerializeObject(updateOrder), time, true); + Logger.Info("update order response: {}", updateOrderResponse); + + //delete order + string deleteOrderResponse = api.delete("/main/api/v2/hashpower/order/" + myOrderId, time, true); + Logger.Info("delete order response: {}", deleteOrderResponse); + + //delete pool + string deletePoolResponse = api.delete("/main/api/v2/pool/" + myPoolId, time, true); + Logger.Info("update pool response: {}", deletePoolResponse); + } + } +} + diff --git a/nuxhash/nhrest/c#/connect/connect/Properties/AssemblyInfo.cs b/nuxhash/nhrest/c#/connect/connect/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a8f931a --- /dev/null +++ b/nuxhash/nhrest/c#/connect/connect/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("connect")] +[assembly: AssemblyDescription("NH new platform API demo")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("NiceHash")] +[assembly: AssemblyProduct("connect")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("25ef6083-e791-4bad-a0c0-462a1a1220e3")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/nuxhash/nhrest/c#/connect/connect/connect.csproj b/nuxhash/nhrest/c#/connect/connect/connect.csproj new file mode 100644 index 0000000..02705ed --- /dev/null +++ b/nuxhash/nhrest/c#/connect/connect/connect.csproj @@ -0,0 +1,72 @@ + + + + + Debug + AnyCPU + {25EF6083-E791-4BAD-A0C0-462A1A1220E3} + Exe + connect + connect + v4.7.2 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll + + + ..\packages\NLog.4.6.5\lib\net45\NLog.dll + + + ..\packages\RestSharp.106.6.10\lib\net452\RestSharp.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuxhash/nhrest/c#/connect/connect/packages.config b/nuxhash/nhrest/c#/connect/connect/packages.config new file mode 100644 index 0000000..fc2293c --- /dev/null +++ b/nuxhash/nhrest/c#/connect/connect/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/nuxhash/nhrest/generate_key.gif b/nuxhash/nhrest/generate_key.gif new file mode 100644 index 0000000..a64e8e1 Binary files /dev/null and b/nuxhash/nhrest/generate_key.gif differ diff --git a/nuxhash/nhrest/java/pom.xml b/nuxhash/nhrest/java/pom.xml new file mode 100644 index 0000000..6f7fd40 --- /dev/null +++ b/nuxhash/nhrest/java/pom.xml @@ -0,0 +1,89 @@ + + + + 4.0.0 + + com.nicehash.connect + connect + 1.0-SNAPSHOT + + connect + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + org.apache.httpcomponents + httpclient + 4.5.6 + + + com.google.code.gson + gson + 2.8.5 + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/nuxhash/nhrest/java/src/main/java/Exch.java b/nuxhash/nhrest/java/src/main/java/Exch.java new file mode 100644 index 0000000..afa724d --- /dev/null +++ b/nuxhash/nhrest/java/src/main/java/Exch.java @@ -0,0 +1,88 @@ +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.nicehash.connect.Api; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.UUID; + +/** + * exchange example + */ +public class Exch +{ + private Log log = LogFactory.getLog(Exch.class); + + private static final String URL_ROOT = "https://api-test.nicehash.com/"; //use https://api2.nicehash.com for production + private static final String ORG_ID = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"; //get it here: https://test.nicehash.com/my/settings/keys or https://new.nicehash.com/my/settings/keys + private static final String API_KEY = "ffffffff-gggg-hhhh-iiii-jjjjjjjjjjjj"; + private static final String API_SECRET = "kkkkkkkk-llll-mmmm-nnnn-oooooooooooooooooooo-pppp-qqqq-rrrr-ssssssssssss"; + + private static final String CURRENCY_SELL = "TBTC"; //user BTC for production + private static final String CURRENCY_BUY = "TLTC"; //use LTC for production + + public static void main( String[] args ) { + new Exch(); + } + + private Exch() { + Api api = new Api(URL_ROOT, ORG_ID, API_KEY, API_SECRET); + + //get server time + String timeResponse = api.get("api/v2/time"); + JsonObject timeObject = new Gson().fromJson(timeResponse, JsonObject.class); + String time = timeObject.get("serverTime").getAsString(); + log.info("server time: " + time); + + //get exchange settings + String exchResponse = api.get("exchange/api/v2/info/status"); + JsonObject exchObject = new Gson().fromJson(exchResponse, JsonObject.class); + //log.info("exchanges: " + exchObject.toString()); + + final JsonObject[] exchanges = new JsonObject[1]; + exchObject.get("symbols").getAsJsonArray().forEach(exch-> { + JsonObject e = exch.getAsJsonObject(); + if (e.get("baseAsset").getAsString().equals(CURRENCY_BUY)) { + exchanges[0] = e; + } + }); + + JsonObject mySettings = exchanges[0]; + log.info("exchange settings: " + mySettings); + + //get balance + String activityResponse = api.get("main/api/v2/accounting/accounts", true, time); + JsonArray accountsArray = new Gson().fromJson(activityResponse, JsonArray.class); + log.info("accounts: " + accountsArray.toString()); + + final double[] balance = new double[1]; + accountsArray.forEach(acc-> { + JsonObject a = acc.getAsJsonObject(); + if (a.get("currency").getAsString().equals(CURRENCY_SELL)) { + balance[0] = a.get("balance").getAsDouble(); + } + }); + + //get order book + String orderBookResponse = api.get("exchange/api/v2/orderbook?market="+CURRENCY_BUY+CURRENCY_SELL+"&limit=100", true, time); + JsonObject orderBookObject = new Gson().fromJson(orderBookResponse, JsonObject.class); + log.info("order book: " + orderBookObject.toString()); + + //cheapest offer for CURRENCY_BUY + JsonArray sellArray = orderBookObject.get("sell").getAsJsonArray(); + JsonArray cheapestArray = sellArray.get(0).getAsJsonArray(); + log.info("cheapest offer price: " + cheapestArray.get(0) + " supply: " + cheapestArray.get(1)); + + double qty = mySettings.get("secMinAmount").getAsDouble()*2; + + //buy with limit order + String url = "exchange/api/v2/order?market="+CURRENCY_BUY+CURRENCY_SELL+"&side=buy&type=limit&quantity="+qty+"&price="+ cheapestArray.get(0); + log.info("order url: " +url); + String orderCreateResponse = api.post(url, null, time, true); + JsonObject orderCreateObject = new Gson().fromJson(orderCreateResponse, JsonObject.class); + log.info("order create: " + orderCreateObject.toString()); + + + } +} diff --git a/nuxhash/nhrest/java/src/main/java/Hpo.java b/nuxhash/nhrest/java/src/main/java/Hpo.java new file mode 100644 index 0000000..0d59426 --- /dev/null +++ b/nuxhash/nhrest/java/src/main/java/Hpo.java @@ -0,0 +1,133 @@ +import com.google.gson.*; +import com.nicehash.connect.Api; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.UUID; + +/** + * hash power order example + */ +public class Hpo +{ + private Log log = LogFactory.getLog(Hpo.class); + + private static final String URL_ROOT = "https://api-test.nicehash.com/"; //use https://api2.nicehash.com for production + private static final String ORG_ID = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"; //get it here: https://test.nicehash.com/my/settings/keys or https://new.nicehash.com/my/settings/keys + private static final String API_KEY = "ffffffff-gggg-hhhh-iiii-jjjjjjjjjjjj"; + private static final String API_SECRET = "kkkkkkkk-llll-mmmm-nnnn-oooooooooooooooooooo-pppp-qqqq-rrrr-ssssssssssss"; + + private static final String ALGORITHM = "X16R"; //algo of your order + private static final String CURRENCY = "TBTC"; //user BTC for production + + public static void main( String[] args ) { + new Hpo(); + } + + private Hpo() { + Api api = new Api(URL_ROOT, ORG_ID, API_KEY, API_SECRET); + + //get server time + String timeResponse = api.get("api/v2/time"); + JsonObject timeObject = new Gson().fromJson(timeResponse, JsonObject.class); + String time = timeObject.get("serverTime").getAsString(); + log.info("server time: " + time); + + //get algo settings + String algosResponse = api.get("main/api/v2/mining/algorithms"); + JsonObject algoObject = new Gson().fromJson(algosResponse, JsonObject.class); + //log.info("algorithms: " + algoObject.toString()); + + final JsonObject[] settings = new JsonObject[1]; + algoObject.get("miningAlgorithms").getAsJsonArray().forEach(acc-> { + JsonObject a = acc.getAsJsonObject(); + if (a.get("algorithm").getAsString().equals(ALGORITHM)) { + settings[0] = a; + } + }); + + JsonObject mySettings = settings[0]; + log.info("algo settings: " + mySettings); + + //get balance + String activityResponse = api.get("main/api/v2/accounting/accounts", true, time); + JsonArray accountsArray = new Gson().fromJson(activityResponse, JsonArray.class); + log.info("accounts: " + accountsArray.toString()); + + final double[] balance = new double[1]; + accountsArray.forEach(acc-> { + JsonObject a = acc.getAsJsonObject(); + if (a.get("currency").getAsString().equals(CURRENCY)) { + balance[0] = a.get("balance").getAsDouble(); + } + }); + + double avaliableBalance = balance[0]; + log.info("balance: " + avaliableBalance + CURRENCY); + + //create new pool + JsonObject pool = new JsonObject(); + pool.addProperty("algorithm", ALGORITHM); + pool.addProperty("name", "my pool "+ UUID.randomUUID().toString()); + pool.addProperty("username", "pool_username"); //your pool username + pool.addProperty("password", "x"); //your pool password + pool.addProperty("stratumHostname", "pool.host.name"); //pool hostname + pool.addProperty("stratumPort", "3456"); //pool port + + //log.info("new pool: " + pool.toString()); + String newPoolResponse = api.post("main/api/v2/pool", pool.toString(), time, false); + //log.info("new pool response: " + newPoolResponse); + JsonObject newPoolResponseObject = new Gson().fromJson(newPoolResponse, JsonObject.class); + //log.info("new pool response object: " + newPoolResponseObject); + + String myPoolId = newPoolResponseObject.get("id").getAsString(); + log.info("new pool id: " + myPoolId); + + //create new order + JsonObject order = new JsonObject(); + order.addProperty("algorithm", ALGORITHM); + order.addProperty("amount", mySettings.get("minimalOrderAmount").getAsString()); + order.addProperty("displayMarketFactor", mySettings.get("displayMarketFactor").getAsString()); + order.addProperty("limit", mySettings.get("minSpeedLimit").getAsString()); // GH [minSpeedLimit-maxSpeedLimit] || 0 - unlimited speed + order.addProperty("market", "EU"); // EU/USA + order.addProperty("marketFactor", mySettings.get("marketFactor").getAsString()); + order.addProperty("poolId", myPoolId); + order.addProperty("price", "0.0010"); //per BTC/GH/day + order.addProperty("type", "STANDARD"); + + //log.info("new order: " + order.toString()); + String newOrderResponse = api.post("main/api/v2/hashpower/order", order.toString(), time, true); + //log.info("new order response: " + newOrderResponse); + JsonObject newOrderResponseObject = new Gson().fromJson(newOrderResponse, JsonObject.class); + //log.info("new order response object: " + newOrderResponseObject); + log.info("new order response object: " + newOrderResponseObject); + + String myOrderId = newOrderResponseObject.get("id").getAsString(); + log.info("new order id: " + myOrderId); + + //update price and limit + JsonObject updateOrder = new JsonObject(); + updateOrder.addProperty("displayMarketFactor", mySettings.get("displayMarketFactor").getAsString()); + updateOrder.addProperty("limit", "0.11"); // GH [minSpeedLimit-maxSpeedLimit] || 0 - unlimited speed + updateOrder.addProperty("marketFactor", mySettings.get("marketFactor").getAsString()); + updateOrder.addProperty("price", "0.00123"); //per BTC/GH/day + + //log.info("update order: " + updateOrder.toString()); + String updateOrderResponse = api.post("main/api/v2/hashpower/order/"+myOrderId+"/updatePriceAndLimit", updateOrder.toString(), time, true); + //log.info("update order response: " + updateOrderResponse); + JsonObject updateOrderResponseObject = new Gson().fromJson(updateOrderResponse, JsonObject.class); + log.info("update order response object: " + updateOrderResponseObject); + + //delete order + String deleteOrderResponse = api.delete("main/api/v2/hashpower/order/"+myOrderId, time, true); + //log.info("delete order response: " + deleteOrderResponse); + JsonObject deleteOrderResponseObject = new Gson().fromJson(deleteOrderResponse, JsonObject.class); + log.info("delete order response object: " + deleteOrderResponseObject); + + //delete pool + String deletePoolResponse = api.delete("main/api/v2/pool/"+myPoolId, time, false); + //log.info("delete pool response: " + deletePoolResponse); + JsonObject deletePoolResponseObject = new Gson().fromJson(deletePoolResponse, JsonObject.class); + log.info("delete pool response object: " + deletePoolResponseObject); + } +} diff --git a/nuxhash/nhrest/java/src/main/java/com/nicehash/connect/Api.java b/nuxhash/nhrest/java/src/main/java/com/nicehash/connect/Api.java new file mode 100644 index 0000000..b0976ec --- /dev/null +++ b/nuxhash/nhrest/java/src/main/java/com/nicehash/connect/Api.java @@ -0,0 +1,189 @@ +package com.nicehash.connect; + +import org.apache.commons.codec.binary.Hex; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.*; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +public class Api { + + private static final Charset CHARSET = StandardCharsets.ISO_8859_1; + private static final String HMAC_SHA256 = "HmacSHA256"; + + private String urlRoot; + private String orgId; + private String apiKey; + private String apiSecret; + + public Api(String urlRoot, String orgId, String apiKey, String apiSecret) { + this.urlRoot = urlRoot; + this.orgId = orgId; + this.apiKey = apiKey; + this.apiSecret = apiSecret; + } + + private static String hashBySegments(String key, String apiKey, String time, String nonce, String orgId, String method, String encodedPath, String query, String bodyStr) { + List segments = Arrays.asList( + apiKey.getBytes(CHARSET), + time.getBytes(CHARSET), + nonce.getBytes(CHARSET), + null, // unused field + orgId.getBytes(CHARSET), + null, // unused field + method.getBytes(CHARSET), + encodedPath == null ? null : encodedPath.getBytes(CHARSET), + query == null ? null : query.getBytes(CHARSET)); + + if (bodyStr != null && bodyStr.length() > 0) { + segments = new ArrayList<>(segments); + segments.add(bodyStr.getBytes(StandardCharsets.UTF_8)); + } + return hmacSha256BySegments(key, segments); + } + + private static String hmacSha256BySegments(String key, List segments) { + try { + Mac mac = Mac.getInstance(HMAC_SHA256); + SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), HMAC_SHA256); + mac.init(secret_key); + boolean first = true; + + for (byte [] segment: segments) { + + if (!first) { + mac.update((byte) 0); + } else { + first = false; + } + + if (segment != null) { + mac.update(segment); + } + } + + return Hex.encodeHexString(mac.doFinal()); + } catch (Exception e) { + throw new RuntimeException("Cannot create HmacSHA256", e); + } + } + + public String get(String url) { + return this.get(url, false, null); + } + + public String get(String url, boolean auth, String time) { + StringBuffer result = new StringBuffer(); + HttpClient client = HttpClientBuilder.create().build(); + HttpGet request = new HttpGet(this.urlRoot+url); + + if (auth) { + String nonce = UUID.randomUUID().toString(); + String digest = Api.hashBySegments(this.apiSecret, this.apiKey, time, nonce, this.orgId, request.getMethod(), request.getURI().getPath(), request.getURI().getQuery(), null); + + request.setHeader("X-Time", time); + request.setHeader("X-Nonce", nonce); + request.setHeader("X-Auth", this.apiKey+":"+digest); + request.setHeader("X-Organization-Id", this.orgId); + } + + try { + HttpResponse response = client.execute(request); + BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); + + String line = ""; + while ((line = rd.readLine()) != null) { + result.append(line); + } + } catch (IOException e) { + e.printStackTrace(); + } + return result.toString(); + } + + public String post(String url, String payload, String time, boolean requestId) { + StringBuffer result = new StringBuffer(); + HttpClient client = HttpClientBuilder.create().build(); + HttpPost request = new HttpPost(this.urlRoot+url); + + StringEntity entity = null; + if (payload != null) { + try { + entity = new StringEntity(payload); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + + request.setEntity(entity); + request.setHeader("Accept", "application/json"); + request.setHeader("Content-type", "application/json"); + + String nonce = UUID.randomUUID().toString(); + String digest = Api.hashBySegments(this.apiSecret, this.apiKey, time, nonce, this.orgId, request.getMethod(), request.getURI().getPath(), request.getURI().getQuery(), payload); + + request.setHeader("X-Time", time); + request.setHeader("X-Nonce", nonce); + request.setHeader("X-Auth", this.apiKey+":"+digest); + request.setHeader("X-Organization-Id", this.orgId); + if (requestId) + request.setHeader("X-Request-Id", UUID.randomUUID().toString()); //must be unique request + + try { + HttpResponse response = client.execute(request); + BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); + + String line = ""; + while ((line = rd.readLine()) != null) { + result.append(line); + } + } catch (IOException e) { + e.printStackTrace(); + } + return result.toString(); + } + + public String delete(String url, String time, boolean requestId) { + StringBuffer result = new StringBuffer(); + HttpClient client = HttpClientBuilder.create().build(); + HttpDelete request = new HttpDelete(this.urlRoot+url); + + String nonce = UUID.randomUUID().toString(); + String digest = Api.hashBySegments(this.apiSecret, this.apiKey, time, nonce, this.orgId, request.getMethod(), request.getURI().getPath(), request.getURI().getQuery(), null); + + request.setHeader("X-Time", time); + request.setHeader("X-Nonce", nonce); + request.setHeader("X-Auth", this.apiKey+":"+digest); + request.setHeader("X-Organization-Id", this.orgId); + if (requestId) + request.setHeader("X-Request-Id", UUID.randomUUID().toString()); //must be unique request + + try { + HttpResponse response = client.execute(request); + BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); + + String line = ""; + while ((line = rd.readLine()) != null) { + result.append(line); + } + } catch (IOException e) { + e.printStackTrace(); + } + return result.toString(); + } +} diff --git a/nuxhash/nhrest/javascript/README.md b/nuxhash/nhrest/javascript/README.md new file mode 100644 index 0000000..d60178f --- /dev/null +++ b/nuxhash/nhrest/javascript/README.md @@ -0,0 +1,11 @@ +### NODE API + +- Install dependencies + + npm install + +- Enter your API key settings into config.js +- Uncomment example you want to run in index.js +- Run with + + node index.js diff --git a/nuxhash/nhrest/javascript/api.js b/nuxhash/nhrest/javascript/api.js new file mode 100644 index 0000000..6f354f5 --- /dev/null +++ b/nuxhash/nhrest/javascript/api.js @@ -0,0 +1,118 @@ +import CryptoJS from "crypto-js"; +import request from "request-promise-native" +import qs from 'qs' + +function createNonce() { + var s = '', length = 32; + do { + s += Math.random().toString(36).substr(2); + } while (s.length < length); + s = s.substr(0, length); + return s; +} + +const getAuthHeader = (apiKey, apiSecret, time, nonce, organizationId = '', request = {}) => { + const hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, apiSecret); + + hmac.update(apiKey); + hmac.update("\0"); + hmac.update(time); + hmac.update("\0"); + hmac.update(nonce); + hmac.update("\0"); + hmac.update("\0"); + if (organizationId) hmac.update(organizationId); + hmac.update("\0"); + hmac.update("\0"); + hmac.update(request.method); + hmac.update("\0"); + hmac.update(request.path); + hmac.update("\0"); + if (request.query) hmac.update(typeof request.query == 'object' ? qs.stringify(request.query) : request.query); + if (request.body) { + hmac.update("\0"); + hmac.update(typeof request.body == 'object' ? JSON.stringify(request.body) : request.body); + } + + return apiKey + ':' + hmac.finalize().toString(CryptoJS.enc.Hex); +}; + + +class Api { + + constructor({locale, apiHost, apiKey, apiSecret, orgId}) { + this.locale = locale || 'en'; + this.host = apiHost; + this.key = apiKey; + this.secret = apiSecret; + this.org = orgId; + this.localTimeDiff = null; + } + + getTime() { + return request({ + uri: this.host + '/api/v2/time', + json: true + }) + .then(res => { + this.localTimeDiff = res.serverTime - (+new Date()); + this.time = res.serverTime; + return res; + }); + } + + apiCall(method, path, {query, body, time} = {}) { + if(this.localTimeDiff === null) { + return Promise.reject(new Error('Get server time first .getTime()')); + } + + // query in path + var [pathOnly,pathQuery] = path.split('?'); + if(pathQuery) query = {...qs.parse(pathQuery), ...query}; + + const nonce = createNonce(); + const timestamp = (time || (+new Date() + this.localTimeDiff)).toString(); + const options = { + uri: this.host + pathOnly, + method: method, + headers: { + 'X-Request-Id': nonce, + 'X-User-Agent': 'NHNodeClient', + 'X-Time': timestamp, + 'X-Nonce': nonce, + 'X-User-Lang': this.locale, + 'X-Organization-Id': this.org, + 'X-Auth': getAuthHeader(this.key, this.secret, timestamp, nonce, this.org, { + method, + path: pathOnly, + query, + body, + }) + }, + qs: query, + body, + json: true + } + + return request(options); + } + + get(path, options) { + return this.apiCall('GET', path, options) + } + + post(path, options) { + return this.apiCall('POST', path, options) + } + + put(path, options) { + return this.apiCall('PUT', path, options) + } + + delete(path, options) { + return this.apiCall('DELETE', path, options) + } + +} + +export default Api diff --git a/nuxhash/nhrest/javascript/config.js b/nuxhash/nhrest/javascript/config.js new file mode 100644 index 0000000..f3fb7be --- /dev/null +++ b/nuxhash/nhrest/javascript/config.js @@ -0,0 +1,6 @@ +export default { + apiHost: 'https://api-test.nicehash.com', //use https://api2.nicehash.com for production + apiKey: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', //get it here: https://test.nicehash.com/my/settings/keys or https://new.nicehash.com/my/settings/keys + apiSecret: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + orgId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', +} diff --git a/nuxhash/nhrest/javascript/exchange.js b/nuxhash/nhrest/javascript/exchange.js new file mode 100644 index 0000000..b040bbc --- /dev/null +++ b/nuxhash/nhrest/javascript/exchange.js @@ -0,0 +1,72 @@ +import config from './config' +import Api from './api' + +var log = function () { + return console.log(...arguments); +} + +var market, orderBook ,order; + +const api = new Api(config); + +// get server time - required +api.getTime() + + .then(() => { + log('server time', api.time) + log('--') + }) + + // get exchange settings + .then(() => api.get('/exchange/api/v2/info/status')) + .then(res => { + market = res.symbols[0]; + log('exchange markets', res); + log('--') + }) + + // get balance + .then(() => api.get('/main/api/v2/accounting/accounts')) + .then(res => { + log('accounts', res); + log('--') + }) + + // get orderbook + .then(() => api.get('/exchange/api/v2/orderbook?aa=1',{query:{market: market.symbol}})) + .then(res => { + orderBook = res; + log('order book for '+market.symbol, res); + log('--') + }) + + // buy with limit order + .then(() => { + var query = { + market: market.symbol, + side: 'buy', + type: 'limit', + quantity: market.secMinAmount * 10, + price: orderBook.sell[0][0], + }; + + return api.post('/exchange/api/v2/order',{query}) + }) + .then(res => { + order = res; + log('new order', res); + log('--') + }) + + // cancel order + .then(() => api.delete('/exchange/api/v2/order',{query:{market: market.symbol, orderId: order. orderId}})) + .then(res => { + orderBook = res; + log('canceled order', res); + log('--') + }) + + .catch(err => { + if(err && err.response) log(err.response.request.method,err.response.request.uri.href); + log('ERROR', err.error || err); + }) diff --git a/nuxhash/nhrest/javascript/hashpower.js b/nuxhash/nhrest/javascript/hashpower.js new file mode 100644 index 0000000..446d1c1 --- /dev/null +++ b/nuxhash/nhrest/javascript/hashpower.js @@ -0,0 +1,107 @@ +import config from './config' +import Api from './api' + +var log = function () { + return console.log(...arguments); +} + +var algo, pool, order; + +const api = new Api(config); + +// get server time - required +api.getTime() + .then(() => { + log('server time', api.time) + log('--') + }) + + // get algo settings + .then(() => api.get('/main/api/v2/mining/algorithms')) + .then(res => { + algo = res.miningAlgorithms[0]; // SCRYPT + log('algorithms', res); + log('--') + }) + + // get balance + // .then(() => api.get('/main/api/v2/accounting/accounts')) + // .then(res => { + // log('accounts', res); + // }) + + //// create new pool + .then(() => { + var body = { + algorithm: 'SCRYPT', + name: 'my pool', + username: 'pool_username', + password: 'x', + stratumHostname: 'pool.host.name', + stratumPort: '3456', + }; + + return api.post('/main/api/v2/pool',{body}) + }) + .then(res => { + pool = res; + log('new pool', res); + log('--') + }) + + // create new order + .then(() => { + var body = { + algorithm: 'SCRYPT', + amount: "0.005", + displayMarketFactor: algo.displayMarketFactor, + limit: algo.minSpeedLimit, + market: 'EU', // or USA + marketFactor: algo.marketFactor, + poolId: pool.id, + price: '0.0010', + type: 'STANDARD', + }; + + return api.post('/main/api/v2/hashpower/order',{body}) + }) + .then(res => { + order = res; + log('new order', res); + log('--') + }) + + // update order price or limit + .then(() => { + var body = { + displayMarketFactor: algo.displayMarketFactor, + marketFactor: algo.marketFactor, + limit: '0.11', + price: '0.00123', + }; + + return api.post(`/main/api/v2/hashpower/order/${order.id}/updatePriceAndLimit`,{body}) + }) + .then(res => { + log('updated order', res); + log('--') + }) + + // cancel order + .then(() => api.delete(`/main/api/v2/hashpower/order/${order.id}`)) + .then(res => { + log('deleted order', res); + log('--') + }) + + // delete pool + .then(() => api.delete(`/main/api/v2/pool/${pool.id}`)) + .then(res => { + log('deleted pool', res); + log('--') + }) + + .catch(err => { + if(err && err.response) log(err.response.request.method,err.response.request.uri.href); + log('ERROR', err.error || err); + }) diff --git a/nuxhash/nhrest/javascript/index.js b/nuxhash/nhrest/javascript/index.js new file mode 100644 index 0000000..2a7a58e --- /dev/null +++ b/nuxhash/nhrest/javascript/index.js @@ -0,0 +1,5 @@ +require = require("esm")(module/*, options*/); + +// examples +//require("./hashpower"); +//require("./exchange"); diff --git a/nuxhash/nhrest/javascript/package-lock.json b/nuxhash/nhrest/javascript/package-lock.json new file mode 100644 index 0000000..16e8617 --- /dev/null +++ b/nuxhash/nhrest/javascript/package-lock.json @@ -0,0 +1,414 @@ +{ + "name": "example-app-node", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bluebird": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "crypto-js": { + "version": "3.1.9-1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz", + "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "requires": { + "mime-db": "1.40.0" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "psl": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.3.0.tgz", + "integrity": "sha512-avHdspHO+9rQTLbv1RO+MPYeP/SzsCoxofjVnHanETfQhTJrmB0HlDoW+EiN/R+C0BZ+gERab9NY0lPN2TxNag==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.8.0.tgz", + "integrity": "sha512-tPSkj8y92PfZVbinY1n84i1Qdx75lZjMQYx9WZhnkofyxzw2r7Ho39G3/aEvSUdebxpnnM4LZJCtvE/Aq3+s9w==" + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + } + } + }, + "request-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.4.tgz", + "integrity": "sha512-8wgMrvE546PzbR5WbYxUQogUnUDfM0S7QIFZMID+J73vdFARkFy+HElj4T+MWYhpXwlLp0EQ8Zoj8xUA0he4Vg==", + "requires": { + "bluebird": "^3.5.0", + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "requires": { + "lodash": "^4.17.11" + } + }, + "request-promise-native": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", + "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", + "requires": { + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + } + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + } + } +} diff --git a/nuxhash/nhrest/javascript/package.json b/nuxhash/nhrest/javascript/package.json new file mode 100644 index 0000000..a678b6a --- /dev/null +++ b/nuxhash/nhrest/javascript/package.json @@ -0,0 +1,19 @@ +{ + "name": "example-app-node", + "version": "0.0.1", + "description": "NiceHash Example App", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "NiceHash", + "license": "ISC", + "dependencies": { + "crypto-js": "^3.1.9-1", + "esm": "^3.2.25", + "qs": "^6.7.0", + "request": "^2.88.0", + "request-promise": "^4.2.4", + "request-promise-native": "^1.0.7" + } +} diff --git a/nuxhash/nhrest/python/README.md b/nuxhash/nhrest/python/README.md new file mode 100644 index 0000000..9f85ea3 --- /dev/null +++ b/nuxhash/nhrest/python/README.md @@ -0,0 +1,87 @@ +# Nicehash python library and command line rest api + +Dependacy +* requests + +To install dependencies run following line your favorite shell console + + pip install requests + + +## Required data and where to get it +Following data is needed: +* api base url: + * https://api2.nicehash.com - Production environment + * https://api-test.nicehash.com - Test environment + +The documentation how to get organisation id, api key and api key secret is here: +https://github.com/nicehash/rest-clients-demo + +## Library usage +Nicehash library is contained in file `nicehash.py`. Api is divided in two part: public and private. + +Code snipplet for public api + + import nicehash + + host = 'https://api2.nicehash.com' + + public_api = nicehash.public_api(host) + + buy_info = public_api.buy_info() + print(buy_info) + + +Code snipplet for private api + + import nicehash + + host = 'https://api2.nicehash.com' + organisation_id = 'Enter your organisation id' + key = 'Enter your api key' + secret = 'Enter your secret for api key' + + private_api = nicehash.private_api(host, organisation_id, key, secret) + + my_accounts = private_api.get_accounts() + print(my_accounts) + + +Usage of other api calls are shown in `test_bot.py` + + +## Command line usage +`nicehash.py` can be used as commad line tools + +To get help run: + + python nicehash.py -h + +Result: + + Usage: nicehash.py [options] + + Options: + -h, --help show this help message and exit + -b BASE, --base_url=BASE + Api base url + -o ORG, --organization_id=ORG + Organization id + -k KEY, --key=KEY Api key + -s SECRET, --secret=SECRET + Secret for api key + -m METHOD, --method=METHOD + Method for request + -p PATH, --path=PATH Path for request + -q PARAMS, --params=PARAMS + Parameters for request + -d BODY, --body=BODY Body for request + + +Example usage: + + python nicehash.py -b https://api2.nicehash.com -o ca5622bd-bc32-451b-90a4-e9ae1088bade -k 85512ceb-4f37-426e-9fb4-929af9134ed1 -s 11260065-37f9-4875-bbdd-52a59ce7775de2c0596c-5c87-4739-bb60-b3f547612aed -m GET -p /main/api/v2/accounting/accounts/ + + + + diff --git a/nuxhash/nhrest/python/nicehash.py b/nuxhash/nhrest/python/nicehash.py new file mode 100644 index 0000000..79b6318 --- /dev/null +++ b/nuxhash/nhrest/python/nicehash.py @@ -0,0 +1,321 @@ +from datetime import datetime +from time import mktime +import uuid +import hmac +import requests +import json +from hashlib import sha256 +import optparse +import sys + + +class public_api: + + def __init__(self, host, verbose=False): + self.host = host + self.verbose = verbose + + def request(self, method, path, query, body): + url = self.host + path + if query: + url += '?' + query + + if self.verbose: + print(method, url) + + s = requests.Session() + if body: + body_json = json.dumps(body) + response = s.request(method, url, data=body_json) + else: + response = s.request(method, url) + + if response.status_code == 200: + return response.json() + elif response.content: + raise Exception(str(response.status_code) + ": " + response.reason + ": " + str(response.content)) + else: + raise Exception(str(response.status_code) + ": " + response.reason) + + def get_current_global_stats(self): + return self.request('GET', '/main/api/v2/public/stats/global/current/', '', None) + + def get_global_stats_24(self): + return self.request('GET', '/main/api/v2/public/stats/global/24h/', '', None) + + def get_active_orders(self): + return self.request('GET', '/main/api/v2/public/orders/active/', '', None) + + def get_active_orders2(self): + return self.request('GET', '/main/api/v2/public/orders/active2/', '', None) + + def buy_info(self): + return self.request('GET', '/main/api/v2/public/buy/info/', '', None) + + def get_algorithms(self): + return self.request('GET', '/main/api/v2/mining/algorithms/', '', None) + + def get_markets(self): + return self.request('GET', '/main/api/v2/mining/markets/', '', None) + + def get_curencies(self): + return self.request('GET', '/api/v2/enum/currencies/', '', None) + + def get_multialgo_info(self): + return self.request('GET', '/main/api/v2/public/simplemultialgo/info/', '', None) + + def get_exchange_markets_info(self): + return self.request('GET', '/exchange/api/v2/info/status', '', None) + + def get_exchange_trades(self, market): + return self.request('GET', '/exchange/api/v2/trades', 'market=' + market, None) + + def get_candlesticks(self, market, from_s, to_s, resolution): + return self.request('GET', '/exchange/api/v2/candlesticks', "market={}&from={}&to={}&resolution={}".format(market, from_s, to_s, resolution), None) + + def get_exchange_orderbook(self, market, limit): + return self.request('GET', '/exchange/api/v2/orderbook', "market={}&limit={}".format(market, limit), None) + +class private_api: + + def __init__(self, host, organisation_id, key, secret, verbose=False): + self.key = key + self.secret = secret + self.organisation_id = organisation_id + self.host = host + self.verbose = verbose + + def request(self, method, path, query, body): + + xtime = self.get_epoch_ms_from_now() + xnonce = str(uuid.uuid4()) + + message = bytearray(self.key, 'utf-8') + message += bytearray('\x00', 'utf-8') + message += bytearray(str(xtime), 'utf-8') + message += bytearray('\x00', 'utf-8') + message += bytearray(xnonce, 'utf-8') + message += bytearray('\x00', 'utf-8') + message += bytearray('\x00', 'utf-8') + message += bytearray(self.organisation_id, 'utf-8') + message += bytearray('\x00', 'utf-8') + message += bytearray('\x00', 'utf-8') + message += bytearray(method, 'utf-8') + message += bytearray('\x00', 'utf-8') + message += bytearray(path, 'utf-8') + message += bytearray('\x00', 'utf-8') + message += bytearray(query, 'utf-8') + + if body: + body_json = json.dumps(body) + message += bytearray('\x00', 'utf-8') + message += bytearray(body_json, 'utf-8') + + digest = hmac.new(bytearray(self.secret, 'utf-8'), message, sha256).hexdigest() + xauth = self.key + ":" + digest + + headers = { + 'X-Time': str(xtime), + 'X-Nonce': xnonce, + 'X-Auth': xauth, + 'Content-Type': 'application/json', + 'X-Organization-Id': self.organisation_id, + 'X-Request-Id': str(uuid.uuid4()) + } + + s = requests.Session() + s.headers = headers + + url = self.host + path + if query: + url += '?' + query + + if self.verbose: + print(method, url) + + if body: + response = s.request(method, url, data=body_json) + else: + response = s.request(method, url) + + if response.status_code == 200: + return response.json() + elif response.content: + raise Exception(str(response.status_code) + ": " + response.reason + ": " + str(response.content)) + else: + raise Exception(str(response.status_code) + ": " + response.reason) + + def get_epoch_ms_from_now(self): + now = datetime.now() + now_ec_since_epoch = mktime(now.timetuple()) + now.microsecond / 1000000.0 + return int(now_ec_since_epoch * 1000) + + def algo_settings_from_response(self, algorithm, algo_response): + algo_setting = None + for item in algo_response['miningAlgorithms']: + if item['algorithm'] == algorithm: + algo_setting = item + + if algo_setting is None: + raise Exception('Settings for algorithm not found in algo_response parameter') + + return algo_setting + + def get_accounts(self): + return self.request('GET', '/main/api/v2/accounting/accounts/', '', None) + + def get_accounts_for_currency(self, currency): + return self.request('GET', '/main/api/v2/accounting/account/' + currency, '', None) + + def get_withdrawal_addresses(self, currency, size, page): + + params = "currency={}&size={}&page={}".format(currency, size, page) + + return self.request('GET', '/main/api/v2/accounting/withdrawalAddresses/', params, None) + + def get_withdrawal_types(self): + return self.request('GET', '/main/api/v2/accounting/withdrawalAddresses/types/', '', None) + + def withdraw_request(self, address_id, amount, currency): + withdraw_data = { + "withdrawalAddressId": address_id, + "amount": amount, + "currency": currency + } + return self.request('POST', '/main/api/v2/accounting/withdrawal/', '', withdraw_data) + + def get_my_active_orders(self, algorithm, market, limit): + + ts = self.get_epoch_ms_from_now() + params = "algorithm={}&market={}&ts={}&limit={}&op=LT".format(algorithm, market, ts, limit) + + return self.request('GET', '/main/api/v2/hashpower/myOrders', params, None) + + def create_pool(self, name, algorithm, pool_host, pool_port, username, password): + pool_data = { + "name": name, + "algorithm": algorithm, + "stratumHostname": pool_host, + "stratumPort": pool_port, + "username": username, + "password": password + } + return self.request('POST', '/main/api/v2/pool/', '', pool_data) + + def delete_pool(self, pool_id): + return self.request('DELETE', '/main/api/v2/pool/' + pool_id, '', None) + + def get_my_pools(self, page, size): + return self.request('GET', '/main/api/v2/pools/', '', None) + + def create_hashpower_order(self, market, type, algorithm, price, limit, amount, pool_id, algo_response): + + algo_setting = self.algo_settings_from_response(algorithm, algo_response) + + order_data = { + "market": market, + "algorithm": algorithm, + "amount": amount, + "price": price, + "limit": limit, + "poolId": pool_id, + "type": type, + "marketFactor": algo_setting['marketFactor'], + "displayMarketFactor": algo_setting['displayMarketFactor'] + } + return self.request('POST', '/main/api/v2/hashpower/order/', '', order_data) + + def cancel_hashpower_order(self, order_id): + return self.request('DELETE', '/main/api/v2/hashpower/order/' + order_id, '', None) + + def refill_hashpower_order(self, order_id, amount): + refill_data = { + "amount": amount + } + return self.request('POST', '/main/api/v2/hashpower/order/' + order_id + '/refill/', '', refill_data) + + def set_price_hashpower_order(self, order_id, price, algorithm, algo_response): + + algo_setting = self.algo_settings_from_response(algorithm, algo_response) + + price_data = { + "price": price, + "marketFactor": algo_setting['marketFactor'], + "displayMarketFactor": algo_setting['displayMarketFactor'] + } + return self.request('POST', '/main/api/v2/hashpower/order/' + order_id + '/updatePriceAndLimit/', '', + price_data) + + def set_limit_hashpower_order(self, order_id, limit, algorithm, algo_response): + algo_setting = self.algo_settings_from_response(algorithm, algo_response) + limit_data = { + "limit": limit, + "marketFactor": algo_setting['marketFactor'], + "displayMarketFactor": algo_setting['displayMarketFactor'] + } + return self.request('POST', '/main/api/v2/hashpower/order/' + order_id + '/updatePriceAndLimit/', '', + limit_data) + + def set_price_and_limit_hashpower_order(self, order_id, price, limit, algorithm, algo_response): + algo_setting = self.algo_settings_from_response(algorithm, algo_response) + + price_data = { + "price": price, + "limit": limit, + "marketFactor": algo_setting['marketFactor'], + "displayMarketFactor": algo_setting['displayMarketFactor'] + } + return self.request('POST', '/main/api/v2/hashpower/order/' + order_id + '/updatePriceAndLimit/', '', + price_data) + + def get_my_exchange_orders(self, market): + return self.request('GET', '/exchange/api/v2/myOrders', 'market=' + market, None) + + def get_my_exchange_trades(self, market): + return self.request('GET','/exchange/api/v2/myTrades', 'market=' + market, None) + + def create_exchange_limit_order(self, market, side, quantity, price): + query = "market={}&side={}&type=limit&quantity={}&price={}".format(market, side, quantity, price) + return self.request('POST', '/exchange/api/v2/order', query, None) + + def create_exchange_buy_market_order(self, market, quantity): + query = "market={}&side=buy&type=market&secQuantity={}".format(market, quantity) + return self.request('POST', '/exchange/api/v2/order', query, None) + + def create_exchange_sell_market_order(self, market, quantity): + query = "market={}&side=sell&type=market&quantity={}".format(market, quantity) + return self.request('POST', '/exchange/api/v2/order', query, None) + + def cancel_exchange_order(self, market, order_id): + query = "market={}&orderId={}".format(market, order_id) + return self.request('DELETE', '/exchange/api/v2/order', query, None) + + +if __name__ == "__main__": + parser = optparse.OptionParser() + + parser.add_option('-b', '--base_url', dest="base", help="Api base url", default="https://api2.nicehash.com") + parser.add_option('-o', '--organization_id', dest="org", help="Organization id") + parser.add_option('-k', '--key', dest="key", help="Api key") + parser.add_option('-s', '--secret', dest="secret", help="Secret for api key") + parser.add_option('-m', '--method', dest="method", help="Method for request", default="GET") + parser.add_option('-p', '--path', dest="path", help="Path for request", default="/") + parser.add_option('-q', '--params', dest="params", help="Parameters for request") + parser.add_option('-d', '--body', dest="body", help="Body for request") + + options, args = parser.parse_args() + + private_api = private_api(options.base, options.org, options.key, options.secret) + + params = '' + if options.params is not None: + params = options.params + + try: + response = private_api.request(options.method, options.path, params, options.body) + except Exception as ex: + print("Unexpected error:", ex) + exit(1) + + print(response) + exit(0) \ No newline at end of file diff --git a/nuxhash/nhrest/python/test_bot.py b/nuxhash/nhrest/python/test_bot.py new file mode 100644 index 0000000..e1df5b4 --- /dev/null +++ b/nuxhash/nhrest/python/test_bot.py @@ -0,0 +1,165 @@ +import nicehash + +# For testing purposes use api-test.nicehash.com. Register here: https://test.nicehash.com + + +# When ready, uncomment line bellow, to run your script on production environment +# host = 'https://api2.nicehash.com' + + +# How to create key, secret and where to get organisation id please check: + + +# Production - https://www.nicehash.com +# host = 'https://api2.nicehash.com' +# organisation_id = 'Enter your organisation id' +# key = 'Enter your api key' +# secret = 'Enter your secret for api key' + + +# # Test - https://test.nicehash.com +# host = 'https://api-test.nicehash.com' +# organisation_id = '286fcf65-d44e-4cdf-81f2-4790c0cbed04' +# key = '6b957253-bcb9-4b83-b431-4f28ab783a6f' +# secret = 'ac09da0c-0b41-49ba-be6f-4698f9c184a67c6a834f-5bfe-5389-ba6f-d9ada9a86c03' + +############################################ +# PUBLIC FUNCTIONS + +# Create public api object +public_api = nicehash.public_api(host, True) + +# Get all algorithms +algorithms = public_api.get_algorithms() +print(algorithms) + +# Get all markets +markets = public_api.get_markets() +print(markets) + +# Get all curencies +currencies = public_api.get_curencies() +print(currencies) + +# Get current global stats +global_stats_current = public_api.get_current_global_stats() +print(global_stats_current) + +# Get global stats for 24h +global_stats_24h = public_api.get_global_stats_24() +print(global_stats_24h) + +# Get orders for certain algorithm +global_active_orders = public_api.get_active_orders() +print(global_active_orders) + +# Buy info +buy_info = public_api.buy_info() +print(buy_info) + +# Get multialgo info +multialgo_info = public_api.get_multialgo_info() +print(multialgo_info) + + +############################################ +# PRIVATE FUNCTIONS + +# Create private api object +private_api = nicehash.private_api(host, organisation_id, key, secret, True) + +# Get balance for all currencies +my_accounts = private_api.get_accounts() +print(my_accounts) + +# Get balance for BTC address +my_btc_account = private_api.get_accounts_for_currency(currencies['currencies'][0]['currency']) +print(my_btc_account) + +# Get my active hashpower orders +my_top_active_x16r_eu_orders = private_api.get_my_active_orders('X16R', 'EU', 10) +print(my_top_active_x16r_eu_orders) + +# Create pool +new_pool = private_api.create_pool('My best pool', 'X16R', 'the.best.pool.com', 3333, 'mybestcoinaddress', 'x') +print(new_pool) + +# Get pools +pools_on_fist_page = private_api.get_my_pools(0, 10) +print(pools_on_fist_page) + +# Create hashpower order +new_order = private_api.create_hashpower_order('EU', 'STANDARD', 'X16R', 0.123, 0, 0.005, pools_on_fist_page['list'][0]['id'], algorithms) +print(new_order) + +# Refill hashpower order +refilled_order = private_api.refill_hashpower_order(new_order['id'], 0.005) +print(refilled_order) + +# Order hashpower set price +set_price_order = private_api.set_price_hashpower_order(new_order['id'], 0.234, 'X16R', algorithms) +print(set_price_order) + +# Order hashpower set limit +set_limit_order = private_api.set_limit_hashpower_order(new_order['id'], 2.12, 'X16R', algorithms) +print(set_limit_order) + +# Order hashpower set price and imit +set_limit_order = private_api.set_price_and_limit_hashpower_order(new_order['id'], 0.235, 1.2, 'X16R', algorithms) +print(set_limit_order) + +# Remove hashpower order +delete_hp_order = private_api.cancel_hashpower_order(new_order['id']) +print(delete_hp_order) + +# Delete pool +delete_pool_result = private_api.delete_pool(new_pool['id']) +print(delete_pool_result) + + +############################################ +# EXCHANGE + +# Get exchange market info +exchange_info = public_api.get_exchange_markets_info() +print(exchange_info) + +# Get trades for first market +trades = public_api.get_exchange_trades(exchange_info['symbols'][0]['symbol']) +print (trades) + +# Get candlesticks +candlesticks = public_api.get_candlesticks(exchange_info['symbols'][0]['symbol'], 1561896404, 1567080464, 60) +print (candlesticks) + +# Get exchange orderbook +exchange_orderbook = public_api.get_exchange_orderbook(exchange_info['symbols'][0]['symbol'], 10) +print (exchange_orderbook) + +# Get my exchange orders +my_exchange_orders = private_api.get_my_exchange_orders(exchange_info['symbols'][0]['symbol']) +print (my_exchange_orders) + +# Get my exchnage trades +my_exchange_trades = private_api.get_my_exchange_trades(exchange_info['symbols'][0]['symbol']) +print (my_exchange_trades) + +# Create buy limit exchange order +new_sell_limit_order = private_api.create_exchange_limit_order(exchange_info['symbols'][0]['symbol'], 'sell', 10, 0.1) +print (new_sell_limit_order) + +# Create sell limit exchange order +new_buy_limit_order = private_api.create_exchange_limit_order(exchange_info['symbols'][0]['symbol'], 'buy', 0.1, 0.1) +print (new_buy_limit_order) + +# Create sell market order +new_sell_market_order = private_api.create_exchange_sell_market_order(exchange_info['symbols'][0]['symbol'], 0.1) +print(new_sell_market_order) + +# Create buy market order +new_buy_market_order = private_api.create_exchange_buy_market_order(exchange_info['symbols'][0]['symbol'], 0.1) +print(new_buy_market_order) + +# Cancel exchange order +cancelled_order = private_api.cancel_exchange_order(exchange_info['symbols'][0]['symbol'], my_exchange_orders[0]['orderId']) +print(cancelled_order)