├── BinanceBot.cpp ├── BinanceBot.h ├── README.md ├── backTest.cpp └── backTest.h /BinanceBot.cpp: -------------------------------------------------------------------------------- 1 | #include "BinanceBot.h" 2 | 3 | void init(); 4 | 5 | auto main(int argc, char* argv[]) -> int 6 | { 7 | cout << endl << "Welcome to the C++ Binance Bot. WARNING --> This is still an extremly early alpha build. Use at your own risk." << endl; 8 | 9 | init(); 10 | return 0; 11 | } 12 | 13 | 14 | void init(){ 15 | string input; 16 | cout << endl << "Choose bot mode: 1 = trading" << endl; 17 | cin >> input; 18 | (input == "1") ? bot.tradingBot() : bot.algoBot(); //TEMPORARY 19 | } 20 | 21 | void botData::setPair(){ 22 | cout << "Select trading pair (ex: LTCBTC, TRXETH, BTCUSDT, etc): " << endl; 23 | cin >> bot.pair; 24 | } 25 | 26 | void botData::setPrice(double foundPrice){ 27 | price = foundPrice; 28 | } 29 | 30 | void botData::setSellPercent(){ 31 | cout << "Enter target gains percentage" << endl; 32 | cin >> sellPercent; 33 | } 34 | 35 | void botData::tradingBot(){ 36 | string choice, amount; 37 | bot.setPair(); 38 | bot.getPrice(pair); 39 | cout << "Selected " << pair << ". Last known price of " << pair << ": " << price; 40 | 41 | cout << "Buying or selling? (1 for buying, 0 for selling)" << endl; 42 | cin >> choice; 43 | (choice == "0") ? choice = "SELL" : choice = "BUY"; 44 | 45 | cout << "Enter the price you would like to buy/sell at." << endl; 46 | cin >> price; 47 | 48 | cout << "Enter amount you would like to buy/sell." << endl; 49 | cin >> amount; 50 | 51 | string curlTest = "curl -H \"X-MBX-APIKEY: "; 52 | // string command = "\" -X POST 'https://api.binance.com/api/v3/order?symbol="+pair+"&side="+choice+"&type=LIMIT&timeInForce=GTC&quantity="+amount+"&price="+price+"&recvWindow=5000×tamp="; 53 | getTime(); 54 | //string message = "symbol="+pair+"&side="+choice+"&type=LIMIT&timeInForce=GTC&quantity="+amount+"&price="+price+"&recvWindow=5000×tamp="+epochTime; 55 | // HMACsha256(message, bot.secretKey); 56 | //curlTest = curlTest+APIKEY+command+time+"&signature="+signature+"'"; 57 | cout << endl << endl << curlTest << endl << endl; 58 | // system(curlTest.c_str()); 59 | 60 | 61 | } 62 | 63 | void botData::algoBot(){ 64 | algoCheck = false; 65 | algoBuy = true; 66 | bot.setPair(); 67 | bot.setSellPercent(); 68 | cout << "Gathering data on pair...This may take some time..." << endl; 69 | getPrice(bot.pair); 70 | cout << "PRICE: " << setprecision(8) << fixed << bot.price << endl; 71 | pastPrice = price; 72 | while(algoCheck == false) 73 | (algoBuy == true) ? checkBuy() : checkSell(); 74 | } 75 | 76 | void botData::checkBuy(){ 77 | bot.getHistoricalPrices(); 78 | bot.calcRSI(); 79 | } 80 | 81 | void botData::calcRSI() 82 | { 83 | vector gain, loss, change, avgGain, avgLoss, RS, RSI; 84 | vector currentPeriod(close.end()-33, close.end()); 85 | double sumGain = 0, sumLoss = 0; 86 | for(int i = 1; i < currentPeriod.size(); i++){ 87 | change.push_back(currentPeriod[i] - currentPeriod[i-1]); 88 | cout << endl << currentPeriod[i] << endl; 89 | } 90 | cout << endl << "******* " << close.back() << endl; 91 | 92 | for(int i = 0; i < change.size(); i++){ 93 | change[i] > 0 ? gain.push_back(change[i]) : gain.push_back(0); 94 | change[i] < 0 ? loss.push_back(abs(change[i])) : loss.push_back(0); 95 | } 96 | for(int i = 0; i < 14; i++){ 97 | sumGain += gain[i]; 98 | sumLoss += loss[i]; 99 | } 100 | avgGain.push_back(sumGain/14); 101 | avgLoss.push_back(sumLoss/14); 102 | cout << endl << "gain: " << avgGain[0] << " loss: " << avgLoss[0] << endl; 103 | for(int i = 14, j = 1; i < gain.size(); i++){ 104 | avgGain.push_back(((avgGain[j-1] * 13)+ gain[i])/14); 105 | avgLoss.push_back(((avgLoss[j-1] * 13)+ loss[i])/14); 106 | j++; 107 | } 108 | 109 | for(int i = 0; i < avgGain.size(); i++) 110 | RS.push_back(avgGain[i]/avgLoss[i]); 111 | 112 | for(int i = 0; i < RS.size(); i++) 113 | avgLoss[i] == 0 ? RSI.push_back(100) : RSI.push_back(100 - (100/(1+RS[i]))); 114 | 115 | 116 | cout << endl << "RSI: " << RSI.back() << endl; 117 | } 118 | 119 | void botData::formatHistoricalPrices(json::value const &value){ //temp 120 | if(!value.is_null()){ 121 | json::value historicalData = value; 122 | ofstream outputFile("test.txt"); //output to file 123 | outputFile << historicalData; //store JSON into file 124 | outputFile.close(); 125 | ifstream inputFile("test.txt"); //input from file 126 | string historicalDataString=""; 127 | string appendTemp; 128 | while(!inputFile.eof()){ 129 | getline(inputFile,appendTemp); //store value from file into string 130 | historicalDataString.append(appendTemp); 131 | } 132 | boost::erase_first(historicalDataString, "["); //formatting for parsing 133 | historicalDataString.append("\"]"); //formatting for parsing 134 | int count = 0; 135 | cout << endl << endl << "------ " << historicalDataString << endl << endl; 136 | string tempHolder; 137 | for (string::iterator it = historicalDataString.begin(); it < historicalDataString.end(); it++){ 138 | if(*it != '[' && *it != '"' && *it !=']'){ 139 | if(*it != ',') 140 | tempHolder.append(1,*it); 141 | else{ 142 | switch (count){ 143 | case 0: 144 | openTime.push_back(stof(tempHolder.c_str())); 145 | break; 146 | case 1: 147 | open.push_back(stof(tempHolder.c_str())); 148 | break; 149 | case 2: 150 | high.push_back(stof(tempHolder.c_str())); 151 | break; 152 | case 3: 153 | low.push_back(stof(tempHolder.c_str())); 154 | break; 155 | case 4: 156 | close.push_back(stof(tempHolder.c_str())); 157 | break; 158 | case 5: 159 | volume.push_back(stof(tempHolder.c_str())); 160 | break; 161 | case 6: 162 | closeTime.push_back(stof(tempHolder.c_str())); 163 | break; 164 | case 7: 165 | quoteAssetVolume.push_back(stof(tempHolder.c_str())); 166 | break; 167 | case 8: 168 | numTrades.push_back(stof(tempHolder.c_str())); 169 | break; 170 | case 9: 171 | takerBuyAssetVol.push_back(stof(tempHolder.c_str())); 172 | break; 173 | case 10: 174 | takerBuyQuoteAssetVol.push_back(stof(tempHolder.c_str())); 175 | break; 176 | case 11: 177 | Ignore.push_back(stof(tempHolder.c_str())); 178 | break; 179 | default: 180 | break; 181 | }//end of switch 182 | (count == 11) ? count = 0 : count++; 183 | tempHolder = ""; 184 | }//end of else 185 | }//end of 2nd if 186 | } //end of for loop 187 | }//end of first if 188 | }//End of function 189 | 190 | void botData::getHistoricalPrices(){ //Get all price data since 1/1/2017 over an interval 191 | //https://api.binance.com/api/v1/klines?symbol=ETHBTC&interval=1h&startTime=1523059200 192 | http_client client(U(RESTfulHost)); 193 | string interval, timestamp = "1483243199000"; 194 | cout << endl << "Enter interval for data collection (Ex: 1h, 2h, 4h, 5m, etc)" << endl; 195 | cin >> interval; 196 | string full_request = "/api/v1/klines?symbol="+pair+"&interval="+interval; 197 | client.request(methods::GET, full_request).then([](http_response response)-> //Do a RESTful GET request on the full URL for the price 198 | pplx::task{ //Result will be in JSON 199 | if(response.status_code() == status_codes::OK){ //If everything went okay, return the JSON (lambda function) 200 | return response.extract_json(); 201 | } 202 | return pplx::task_from_result(json::value()); 203 | }) 204 | .then([](pplx::task previousTask){ 205 | try{ 206 | json::value const & v = previousTask.get(); //Take the JSON gathered by the GET request and store it into CPP JSON object 207 | bot.formatHistoricalPrices(v); 208 | } 209 | catch (http_exception const & e){ //This is just here to output an error if one occurs. 210 | wcout << e.what() << endl; 211 | } 212 | }).wait(); //Wait for all to finish 213 | } 214 | 215 | void botData::checkSell(){ 216 | getPrice(bot.pair); 217 | double difference; 218 | cout << endl << "PRICE: " << setprecision(8) << fixed << bot.price << endl; 219 | if(price > pastPrice){ 220 | difference = ((price - pastPrice)/price)*100; 221 | cout << endl << "DIFF: " << difference << endl; 222 | 223 | if(difference >= sellPercent){ 224 | cout << "We should sell." << endl; 225 | } 226 | } 227 | } 228 | 229 | 230 | void printPrice(json::value const &value){ //temp 231 | if(!value.is_null()){ 232 | json::value test = value; 233 | string v = test["price"].as_string(); 234 | double price = stof(v.c_str()); 235 | bot.setPrice(price); 236 | // cout << test["price"] << endl << v << endl; 237 | } 238 | 239 | } 240 | 241 | void botData::getPrice(const string pair){ 242 | http_client client(U(RESTfulHost)); //The base connection for the RESTful API 243 | string full_request = "/api/v3/ticker/price?symbol=" + pair; //The rest of the URL we are going to ping to the price 244 | client.request(methods::GET, full_request).then([](http_response response)-> //Do a RESTful GET request on the full URL for the price 245 | pplx::task{ //Result will be in JSON 246 | if(response.status_code() == status_codes::OK){ //If everything went okay, return the JSON (lambda function) 247 | return response.extract_json(); 248 | } 249 | return pplx::task_from_result(json::value()); 250 | }) 251 | .then([](pplx::task previousTask){ 252 | try{ 253 | json::value const & v = previousTask.get(); //Take the JSON gathered by the GET request and store it into CPP JSON object 254 | printPrice(v); //pass that object to the print price 255 | } 256 | catch (http_exception const & e){ //This is just here to output an error if one occurs. 257 | wcout << e.what() << endl; 258 | } 259 | }).wait(); //Wait for all to finish 260 | } 261 | 262 | inline auto binary_to_hex_digit(unsigned a) -> char{ 263 | return a + (a < 10 ? '0' : 'a' - 10); 264 | } 265 | 266 | auto binary_to_hex(unsigned char const* binary, unsigned binary_len) -> string { 267 | string r(binary_len * 2, '\0'); 268 | for(unsigned i = 0; i < binary_len; ++i) { 269 | r[i * 2] = binary_to_hex_digit(binary[i] >> 4); 270 | r[i * 2 + 1] = binary_to_hex_digit(binary[i] & 15); 271 | } 272 | return r; 273 | } 274 | 275 | void botData::HMACsha256(string const& message, string const& key) { 276 | unsigned char result[EVP_MAX_MD_SIZE]; 277 | unsigned result_len = 0; 278 | HMAC(EVP_sha256(), key.data(), key.size(), reinterpret_cast(message.data()), message.size(), result, &result_len); 279 | signature = binary_to_hex(result, result_len); 280 | } 281 | 282 | void botData::getTime(){ 283 | struct timeval tp; 284 | gettimeofday(&tp, NULL); 285 | long long mslong = (long long) tp.tv_sec * 1000L + tp.tv_usec / 1000; 286 | string time = to_string(mslong); 287 | } 288 | -------------------------------------------------------------------------------- /BinanceBot.h: -------------------------------------------------------------------------------- 1 | #ifndef BinanceBot_h 2 | #define BinanceBot_h 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include //Allows one to see prices of small satoshi's worth coins. 14 | #include //File opens/closes 15 | #include 16 | #include //Boost::erase 17 | #include //abs val 18 | 19 | using namespace utility; // Common utilities like string conversions 20 | using namespace web; // Common features like URIs. 21 | using namespace web::http; // Common HTTP functionality 22 | using namespace web::http::client; // HTTP client features 23 | using namespace concurrency::streams; // Asynchronous streams 24 | using namespace std; 25 | using namespace std::chrono; //Allows us to get epoch time without having to ping Binance server for it 26 | 27 | #define RESTfulHost "https://api.binance.com/" 28 | 29 | class botData{ 30 | double price,pastPrice,sellPercent,RSI; 31 | vector openTime,closeTime,numTrades; 32 | vector open, high, low, close, volume, quoteAssetVolume,takerBuyAssetVol,takerBuyQuoteAssetVol,Ignore; 33 | bool algoCheck,algoBuy; 34 | string pair; 35 | string epochTime; 36 | string signature; //THIS IS THE HMAC SHA256 SIGNATURE. USES MESSAGE AND YOUR SECRET API KEY 37 | string secretKey = "YOUR SECRET KEY HERE"; //THIS IS THE KEY FOR THE HMAC SHA256 38 | string APIKEY = "YOUR KEY HERE"; 39 | 40 | public: 41 | void setPair(); 42 | void setPrice(double foundPrice); 43 | void setSellPercent(); 44 | void init(); 45 | void tradingBot(); 46 | void algoBot(); 47 | void getPrice(const string); 48 | void formatPrice(json::value const &); 49 | void getTime(); //Get epoch time (It will be needed for the signature) 50 | void HMACsha256(string const&, string const&); 51 | void checkBuy(); 52 | void checkSell(); 53 | void getHistoricalPrices(); 54 | void formatHistoricalPrices(json::value const &); 55 | void calcRSI(); 56 | 57 | 58 | }bot; 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | #endif /* BinanceBot_h */ 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **NOTE: THIS PROJECT HAS BEEN DISCONTINUED, FURTHER ALGO BOT WORK CAN BE FOUND AT https://github.com/Chudleyj/AlgoBot 2 | 3 | # Binance-Trading-Bot 4 | A C++ bot that uses Bianance's RESTful API alongside Microsoft's C++ RESTsdk 5 | 6 | Back testing of this bot is now up and running. It is using a simple algorithm but works 100%. So far, the algorithm has shown 5% profits over a 30 day period. Algorithm definetly needs massive improvements and far more technical indictaors, but the framework of this bot works. 7 | 8 | Binance API: https://github.com/binance-exchange/binance-official-api-docs 9 | 10 | Prerequisites: 11 | 12 | https://github.com/Microsoft/cpprestsdk 13 | 14 | C++ 11 or higher 15 | 16 | To Run: 17 | g++ -std=c++11 BinanceBot.cpp -stdlib=libc++ -lcpprest -lssl -lcrypto -t/openssl/lib -I/usr/local/opt/openssl/include-mt -L/usr/local/opt 18 | -------------------------------------------------------------------------------- /backTest.cpp: -------------------------------------------------------------------------------- 1 | #include "backTest.h" 2 | 3 | void init(); 4 | 5 | auto main(int argc, char* argv[]) -> int{ 6 | cout << endl << "Welcome to the C++ Binance Bot. WARNING --> This is still an extremly early alpha build. Use at your own risk." << endl << flush; 7 | // init(); 8 | backTest.backTest(); 9 | return 0; 10 | } 11 | 12 | void init(){ 13 | string input; 14 | cout << endl << "Choose bot mode: 1 = trading" << endl; 15 | cin >> input; 16 | //(input == "1") ? priceData.tradingBot() : algoBot.algoBot(); //TEMPORARY 17 | } 18 | 19 | void serverData::setPair(){ 20 | cout << "Select trading pair (ex: LTCBTC, TRXETH, BTCUSDT, etc): " << endl; 21 | cin >> pair; 22 | } 23 | 24 | void serverData::inputPrice(double foundPrice){ 25 | price = foundPrice; 26 | } 27 | 28 | void serverData::setPrice(){ 29 | http_client client(U(RESTfulHost)); //The base connection for the RESTful API 30 | string full_request = "/api/v3/ticker/price?symbol=" + pair; //The rest of the URL we are going to ping to the price 31 | client.request(methods::GET, full_request).then([](http_response response)-> //Do a RESTful GET request on the full URL for the price 32 | pplx::task{ //Result will be in JSON 33 | if(response.status_code() == status_codes::OK){ //If everything went okay, return the JSON (lambda function) 34 | return response.extract_json(); 35 | } 36 | return pplx::task_from_result(json::value()); 37 | }) 38 | .then([](pplx::task previousTask){ 39 | try{ 40 | json::value const & v = previousTask.get(); //Take the JSON gathered by the GET request and store it into CPP JSON object 41 | printPrice(v); //pass that object to the print price 42 | } 43 | catch (http_exception const & e){ //This is just here to output an error if one occurs. 44 | wcout << e.what() << endl; 45 | } 46 | }).wait(); //Wait for all to finish 47 | } 48 | 49 | /* void botData::tradingBot(){ 50 | string choice, amount; 51 | bot.setPair(); 52 | bot.getPrice(); 53 | cout << "Selected " << pair << ". Last known price of " << pair << ": " << price; 54 | 55 | cout << "Buying or selling? (1 for buying, 0 for selling)" << endl; 56 | cin >> choice; 57 | (choice == "0") ? choice = "SELL" : choice = "BUY"; 58 | 59 | cout << "Enter the price you would like to buy/sell at." << endl; 60 | cin >> price; 61 | 62 | cout << "Enter amount you would like to buy/sell." << endl; 63 | cin >> amount; 64 | string curlTest = "curl -H \"X-MBX-APIKEY: "; 65 | // string command = "\" -X POST 'https://api.binance.com/api/v3/order?symbol="+pair+"&side="+choice+"&type=LIMIT&timeInForce=GTC&quantity="+amount+"&price="+price+"&recvWindow=5000×tamp="; 66 | getTime(); 67 | //string message = "symbol="+pair+"&side="+choice+"&type=LIMIT&timeInForce=GTC&quantity="+amount+"&price="+price+"&recvWindow=5000×tamp="+epochTime; 68 | // HMACsha256(message, bot.secretKey); 69 | //curlTest = curlTest+APIKEY+command+time+"&signature="+signature+"'"; 70 | cout << endl << endl << curlTest << endl << endl; 71 | // system(curlTest.c_str()); 72 | 73 | 74 | }*/ 75 | 76 | void serverData::HMACsha256(string const& message, string const& key) { 77 | unsigned char result[EVP_MAX_MD_SIZE]; 78 | unsigned result_len = 0; 79 | HMAC(EVP_sha256(), key.data(), key.size(), reinterpret_cast(message.data()), message.size(), result, &result_len); 80 | servData.setSignature(binary_to_hex(result, result_len)); 81 | } 82 | 83 | void serverData::getTime(){ 84 | struct timeval tp; 85 | gettimeofday(&tp, NULL); 86 | long long mslong = (long long) tp.tv_sec * 1000L + tp.tv_usec / 1000; 87 | string time = to_string(mslong); 88 | } 89 | 90 | void backTesting::getTotal(){ 91 | total=0; 92 | double test = 0; 93 | 94 | if(BTC>0){ 95 | servData.inputPair("BTCUSDT"); 96 | servData.inputPrice(0); 97 | servData.setPrice(); 98 | test = BTC * servData.getPrice(); 99 | total += test; 100 | } 101 | 102 | 103 | if(LTC>0){ 104 | servData.inputPair("LTCUSDT"); 105 | servData.inputPrice(0); 106 | servData.setPrice(); 107 | test = LTC * servData.getPrice(); 108 | total += test; 109 | } 110 | 111 | if(ETH>0){ 112 | servData.inputPair("ETHUSDT"); 113 | servData.inputPrice(0); 114 | servData.setPrice(); 115 | test = ETH * servData.getPrice(); 116 | total += test; 117 | } 118 | 119 | if(BCC>0){ 120 | servData.inputPair("BCCUSDT"); 121 | servData.inputPrice(0); 122 | servData.setPrice(); 123 | test = BCC * servData.getPrice(); 124 | total += test; 125 | } 126 | 127 | if(BNB>0){ 128 | servData.inputPair("BNBUSDT"); 129 | servData.inputPrice(0); 130 | servData.setPrice(); 131 | test = BNB * servData.getPrice(); 132 | total += test; 133 | } 134 | 135 | if(NEO>0){ 136 | servData.inputPair("NEOUSDT"); 137 | servData.inputPrice(0); 138 | servData.setPrice(); 139 | test = NEO * servData.getPrice(); 140 | total += test; 141 | } 142 | 143 | if(ADA>0){ 144 | servData.inputPair("ADAUSDT"); 145 | servData.inputPrice(0); 146 | servData.setPrice(); 147 | test = ADA * servData.getPrice(); 148 | total += test; 149 | } 150 | 151 | if(QTUM>0){ 152 | servData.inputPair("QTUMUSDT"); 153 | servData.inputPrice(0); 154 | servData.setPrice(); 155 | test = QTUM * servData.getPrice(); 156 | total += test; 157 | } 158 | 159 | double temp = total + USDT; 160 | string input = "\n\nTotal: " + to_string(temp); 161 | cout << endl << input << endl; 162 | ofstream account("backTest.txt", ofstream::out|ofstream::app); 163 | account << input; 164 | account.close(); 165 | } 166 | 167 | void backTesting::simSell(){ 168 | string append; 169 | servData.setPrice(); 170 | string pair = servData.getPair(); 171 | double price = servData.getPrice(); 172 | if(pair == "BTCUSDT"){ 173 | this->USDT = this->USDT + this->BTC * price; 174 | append = "Sold " + to_string(this->BTC) + "BTC for a total of: $" + to_string(BTC*price); 175 | this->BTC = 0; 176 | } 177 | else if(pair == "ETHUSDT"){ 178 | this->USDT = this->USDT + this->ETH * price; 179 | append = "Sold " + to_string(this->ETH) + "ETH for a total of: $" + to_string(ETH*price); 180 | this->ETH = 0; 181 | } 182 | else if(pair == "BCCUSDT"){ 183 | this->USDT = this->USDT + this->BCC * price; 184 | append = "Sold " + to_string(this->BCC) + "BCC for a total of: $" + to_string(BCC*price); 185 | this->BCC = 0; 186 | } 187 | else if(pair == "LTCUSDT"){ 188 | this->USDT = this->USDT + this->LTC * price; 189 | append = "Sold " + to_string(this->LTC) + "LTC for a total of: $" + to_string(LTC*price); 190 | this->LTC = 0; 191 | } 192 | else if(pair == "BNBUSDT"){ 193 | this->USDT = this->USDT + this->BNB * price; 194 | append = "Sold " + to_string(this->BNB) + "BNB for a total of: $" + to_string(BNB*price); 195 | this->BNB = 0; 196 | } 197 | else if(pair == "NEOUSDT"){ 198 | this->USDT = this->USDT + this->NEO * price; 199 | append = "Sold " + to_string(this->NEO) + "NEO for a total of: $" + to_string(NEO*price); 200 | this->NEO = 0; 201 | } 202 | else if(pair == "ADAUSDT"){ 203 | this->USDT = this->USDT + this->ADA * price; 204 | append = "Sold " + to_string(this->ADA) + "ADA for a total of: $" + to_string(ADA*price); 205 | this->ADA = 0; 206 | } 207 | else{ 208 | this->USDT = this->USDT + this->QTUM * price; 209 | append = "Sold " + to_string(this->QTUM) + "QTUM for a total of: $" + to_string(QTUM*price); 210 | this->QTUM = 0; 211 | } 212 | 213 | string trade = "\n\nFound sell. Making sell on pair " + pair + " at price: $" + to_string(price) + ".\n" + append + "\n USDT remaining: " + to_string(USDT); 214 | cout << endl << endl << trade << endl << endl; 215 | 216 | ofstream account("backTest.txt", ofstream::out|ofstream::app); 217 | account << trade; 218 | account.close(); 219 | } 220 | 221 | void backTesting::simBuy(){ 222 | if(USDT > 0){ 223 | string append; 224 | double buy; 225 | double purchaseAmt = USDT * 25 / 100; 226 | USDT = USDT - purchaseAmt; 227 | servData.setPrice(); 228 | string pair = servData.getPair(); 229 | double price = servData.getPrice(); 230 | 231 | if(pair == "BTCUSDT"){ 232 | buy = purchaseAmt/price; 233 | BTC = buy + BTC; 234 | append = "Purchased " + to_string(buy) + "BTC for a total of: $" + to_string(purchaseAmt); 235 | } 236 | else if(pair == "ETHUSDT"){ 237 | buy = purchaseAmt/price; 238 | ETH = buy + ETH; 239 | append = "Purchased " + to_string(buy)+ "ETH for a total of: $" + to_string(purchaseAmt); 240 | } 241 | else if(pair == "BCCUSDT"){ 242 | buy = purchaseAmt/price; 243 | BCC = buy + BCC; 244 | append = "Purchased " + to_string(buy) + "BCC for a total of: $" + to_string(purchaseAmt); 245 | } 246 | else if(pair == "LTCUSDT"){ 247 | buy = purchaseAmt/price; 248 | LTC = buy + LTC; 249 | append = "Purchased " + to_string(buy) + "LTC for a total of: $" + to_string(purchaseAmt); 250 | } 251 | else if(pair == "BNBUSDT"){ 252 | buy = purchaseAmt/price; 253 | BNB = buy + BNB; 254 | append = "Purchased " + to_string(buy) + "BNB for a total of: $" + to_string(purchaseAmt); 255 | } 256 | else if(pair == "NEOUSDT"){ 257 | buy = purchaseAmt/price; 258 | NEO = buy + NEO; 259 | append = "Purchased " + to_string(buy) + "NEO for a total of: $" + to_string(purchaseAmt); 260 | } 261 | else if(pair == "ADAUSDT"){ 262 | buy = purchaseAmt/price; 263 | ADA = buy + ADA; 264 | append = "Purchased " + to_string(buy) + "ADA for a total of: $" + to_string(purchaseAmt); 265 | } 266 | else{ 267 | buy = purchaseAmt/price; 268 | QTUM = buy + QTUM; 269 | append = "Purchased " + to_string(buy) + "QTUM for a total of: $" + to_string(purchaseAmt); 270 | } 271 | 272 | string trade = "\n\nFound buy. Making buy on pair " + pair + " at price: $" + to_string(price) + ".\n" + append + "\n USDT remaining: " + to_string(USDT);; 273 | cout << endl << endl << trade << endl << endl; 274 | ofstream account("backTest.txt", ofstream::out|ofstream::app); 275 | account << trade; 276 | account.close(); 277 | } 278 | } 279 | 280 | void backTesting::backTest(){ 281 | USDT = 1000; 282 | double total=0; 283 | int count = 0; 284 | long double RSIcheck; 285 | while(1){ 286 | servData.inputPair("BTCUSDT"); 287 | algoBot.checkBuy(); 288 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 289 | if(RSIcheck < 40.0 && BTC == 0) 290 | simBuy(); 291 | 292 | servData.inputPair("LTCUSDT"); 293 | algoBot.checkBuy(); 294 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 295 | if(RSIcheck < 40.0 && LTC == 0) 296 | simBuy(); 297 | 298 | servData.inputPair("ETHUSDT"); 299 | algoBot.checkBuy(); 300 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 301 | if(RSIcheck < 40.0 && ETH == 0) 302 | simBuy(); 303 | 304 | servData.inputPair("BCCUSDT"); 305 | algoBot.checkBuy(); 306 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 307 | if(RSIcheck < 40.0 && BCC == 0) 308 | simBuy(); 309 | 310 | servData.inputPair("BNBUSDT"); 311 | algoBot.checkBuy(); 312 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 313 | if(RSIcheck < 40.0 && BNB == 0) 314 | simBuy(); 315 | 316 | servData.inputPair("NEOUSDT"); 317 | algoBot.checkBuy(); 318 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 319 | if(RSIcheck < 40.0 && NEO == 0) 320 | simBuy(); 321 | 322 | servData.inputPair("ADAUSDT"); 323 | algoBot.checkBuy(); 324 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 325 | if(RSIcheck < 40.0 && ADA == 0) 326 | simBuy(); 327 | 328 | servData.inputPair("QTUMUSDT"); 329 | algoBot.checkBuy(); 330 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 331 | if(RSIcheck < 40.0 && QTUM == 0) 332 | simBuy(); 333 | //---------------// 334 | 335 | servData.inputPair("BTCUSDT"); 336 | algoBot.checkBuy(); 337 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 338 | if(RSIcheck > 60.0 && BTC > 0) 339 | simSell(); 340 | 341 | servData.inputPair("LTCUSDT"); 342 | algoBot.checkBuy(); 343 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 344 | if(RSIcheck > 60.0 && LTC > 0) 345 | simSell(); 346 | 347 | servData.inputPair("ETHUSDT"); 348 | algoBot.checkBuy(); 349 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 350 | if(RSIcheck > 60.0 && ETH > 0) 351 | simSell(); 352 | 353 | servData.inputPair("BCCUSDT"); 354 | algoBot.checkBuy(); 355 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 356 | if(RSIcheck > 60.0 && BCC > 0) 357 | simSell(); 358 | 359 | servData.inputPair("BNBUSDT"); 360 | algoBot.checkBuy(); 361 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 362 | if(RSIcheck > 60.0 && BNB > 0) 363 | simSell(); 364 | 365 | servData.inputPair("NEOUSDT"); 366 | algoBot.checkBuy(); 367 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 368 | if(RSIcheck > 60.0 && NEO > 0) 369 | simSell(); 370 | 371 | servData.inputPair("ADAUSDT"); 372 | algoBot.checkBuy(); 373 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 374 | if(RSIcheck > 60.0 && ADA > 0) 375 | simSell(); 376 | 377 | servData.inputPair("QTUMUSDT"); 378 | algoBot.checkBuy(); 379 | RSIcheck = TechnicalAnalysisCalcs.getRSIback(); 380 | if(RSIcheck > 60.0 && QTUM > 0) 381 | simSell(); 382 | (count == 50) ? (getTotal(), count = 0) : (count++); 383 | } 384 | } 385 | 386 | void algorithmBot::setSellPercent(){ 387 | cout << "Enter target gains percentage" << endl; 388 | cin >> sellPercent; 389 | } 390 | 391 | void algorithmBot::algoBot(){ 392 | algoCheck = false; 393 | algoBuy = true; 394 | servData.setPair(); 395 | // bot.setSellPercent(); 396 | cout << "Gathering data on pair...This may take some time..." << endl; 397 | servData.setPrice(); 398 | //cout << "PRICE: " << setprecision(8) << fixed << algoBot.getPrice() << endl; 399 | //pastPrice = servData.getPrice(); 400 | //while(algoCheck == false) 401 | // (algoBuy == true) ? checkBuy() : checkSell(); 402 | } 403 | 404 | void algorithmBot::checkBuy(){ 405 | priceData.getHistoricalPrices(); 406 | TechnicalAnalysisCalcs.calcRSI(); 407 | // algoBot.calcStochRSI(); 408 | } 409 | 410 | /*void algorithmBot::checkSell(){ 411 | double currentPrice = servData.getPrice(); 412 | double difference; 413 | cout << endl << "PRICE: " << setprecision(8) << fixed << currentPrice << endl; 414 | if(price > pastPrice){ 415 | difference = ((currentPrice - pastPrice)/price)*100; 416 | cout << endl << "DIFF: " << difference << endl; 417 | 418 | if(difference >= sellPercent){ 419 | cout << "We should sell." << endl; 420 | } 421 | } 422 | }*/ 423 | 424 | void TechnicalAnalysis::calcStochRSI(){ 425 | vector highest, lowest; 426 | long double temp=0; 427 | int startingPoint = 0; 428 | 429 | 430 | for(int i = 0; i < RSI.size()-14; i++){ 431 | vector::iterator lowIt=min_element(RSI.begin()+i,RSI.begin()+i+13); 432 | vector::iterator highIt=max_element(RSI.begin()+i,RSI.begin()+i+13); 433 | 434 | highest.push_back(*highIt); 435 | lowest.push_back(*lowIt); 436 | i++; 437 | } 438 | 439 | for(int i =0; i < highest.size(); i++){ 440 | temp = (RSI[i+13]-lowest[i])/(highest[i]-lowest[i]); 441 | stochRSI.push_back(temp); 442 | temp=0; 443 | } 444 | 445 | cout << endl << "STOCH RSI: " << stochRSI.back() << endl; 446 | 447 | } 448 | 449 | void TechnicalAnalysis::calcRSI(){ 450 | RSI.clear(); 451 | vector gain, loss, change, avgGain, avgLoss, RS; 452 | vector currentPeriod(priceData.close.end()-250, priceData.close.end()); 453 | double sumGain = 0, sumLoss = 0; 454 | 455 | for(int i = 1; i < currentPeriod.size(); i++) 456 | change.push_back(currentPeriod[i] - currentPeriod[i-1]); 457 | 458 | for(int i = 0; i < change.size(); i++){ 459 | change[i] > 0 ? gain.push_back(change[i]) : gain.push_back(0); 460 | change[i] < 0 ? loss.push_back(abs(change[i])) : loss.push_back(0); 461 | sumGain += gain[i]; 462 | sumLoss += loss[i]; 463 | } 464 | 465 | avgGain.push_back(sumGain/14); 466 | avgLoss.push_back(sumLoss/14); 467 | 468 | for(int i = 14, j = 1; i < gain.size(); i++){ 469 | avgGain.push_back(((avgGain[j-1] * 13)+ gain[i])/14); 470 | avgLoss.push_back(((avgLoss[j-1] * 13)+ loss[i])/14); 471 | j++; 472 | } 473 | 474 | for(int i = 0; i < avgGain.size(); i++){ 475 | RS.push_back(avgGain[i]/avgLoss[i]); 476 | avgLoss[i] == 0 ? RSI.push_back(100) : RSI.push_back(100 - (100/(1+RS[i]))); 477 | } 478 | } 479 | 480 | //Clear all vectors of old coin pair or old data to allow most up to date data. 481 | void pricingData::clearVecs(){ 482 | priceData.openTime.clear(); 483 | priceData.open.clear(); 484 | priceData.high.clear(); 485 | priceData.low.clear(); 486 | priceData.close.clear(); 487 | priceData.volume.clear(); 488 | priceData.closeTime.clear(); 489 | priceData.quoteAssetVolume.clear(); 490 | priceData.numTrades.clear(); 491 | priceData.takerBuyAssetVol.clear(); 492 | priceData.takerBuyQuoteAssetVol.clear(); 493 | priceData.ignore.clear(); 494 | } 495 | 496 | void pricingData::formatHistoricalPrices(json::value const &value){ //temp 497 | priceData.clearVecs(); 498 | if(!value.is_null()){ 499 | json::value historicalData = value; 500 | ofstream outputFile; 501 | outputFile.open("test.txt",ofstream::out | ofstream::trunc); //output to file 502 | outputFile << historicalData; //store JSON into file 503 | outputFile.close(); 504 | ifstream inputFile("test.txt"); //input from file 505 | string historicalDataString=""; 506 | string appendTemp; 507 | while(!inputFile.eof()){ 508 | getline(inputFile,appendTemp); //store value from file into string 509 | historicalDataString.append(appendTemp); 510 | } 511 | boost::erase_first(historicalDataString, "["); //formatting for parsing 512 | historicalDataString.append("\"]"); //formatting for parsing 513 | int count = 0; 514 | string tempHolder; 515 | for (string::iterator it = historicalDataString.begin(); it < historicalDataString.end(); it++){ 516 | if(*it != '[' && *it != '"' && *it !=']'){ 517 | if(*it != ',') 518 | tempHolder.append(1,*it); 519 | else{ 520 | switch (count){ 521 | case 0: 522 | priceData.openTime.push_back(stof(tempHolder.c_str())); 523 | break; 524 | case 1: 525 | priceData.open.push_back(stof(tempHolder.c_str())); 526 | break; 527 | case 2: 528 | priceData.high.push_back(stof(tempHolder.c_str())); 529 | break; 530 | case 3: 531 | priceData.low.push_back(stof(tempHolder.c_str())); 532 | break; 533 | case 4: 534 | priceData.close.push_back(stof(tempHolder.c_str())); 535 | break; 536 | case 5: 537 | priceData.volume.push_back(stof(tempHolder.c_str())); 538 | break; 539 | case 6: 540 | priceData.closeTime.push_back(stof(tempHolder.c_str())); 541 | break; 542 | case 7: 543 | priceData.quoteAssetVolume.push_back(stof(tempHolder.c_str())); 544 | break; 545 | case 8: 546 | priceData.numTrades.push_back(stof(tempHolder.c_str())); 547 | break; 548 | case 9: 549 | priceData.takerBuyAssetVol.push_back(stof(tempHolder.c_str())); 550 | break; 551 | case 10: 552 | priceData.takerBuyQuoteAssetVol.push_back(stof(tempHolder.c_str())); 553 | break; 554 | case 11: 555 | priceData.ignore.push_back(stof(tempHolder.c_str())); 556 | break; 557 | default: 558 | break; 559 | }//end of switch 560 | (count == 11) ? count = 0 : count++; 561 | tempHolder = ""; 562 | }//end of else 563 | }//end of 2nd if 564 | } //end of for loop 565 | }//end of first if 566 | }//End of function 567 | 568 | void pricingData::getHistoricalPrices(){ //Get all price data since 1/1/2017 over an interval 569 | //https://api.binance.com/api/v1/klines?symbol=ETHBTC&interval=1h&startTime=1523059200 570 | http_client client(U(RESTfulHost)); 571 | string interval, timestamp = "1483243199000"; 572 | interval = "5m"; 573 | string full_request = "/api/v1/klines?symbol="+servData.getPair()+"&interval="+interval; 574 | client.request(methods::GET, full_request).then([](http_response response)-> //Do a RESTful GET request on the full URL for the price 575 | pplx::task{ //Result will be in JSON 576 | if(response.status_code() == status_codes::OK){ //If everything went okay, return the JSON (lambda function) 577 | return response.extract_json(); 578 | } 579 | return pplx::task_from_result(json::value()); 580 | }) 581 | .then([](pplx::task previousTask){ 582 | try{ 583 | json::value const & v = previousTask.get(); //Take the JSON gathered by the GET request and store it into CPP JSON object 584 | priceData.formatHistoricalPrices(v); 585 | } 586 | catch (http_exception const & e){ //This is just here to output an error if one occurs. 587 | wcout << e.what() << endl; 588 | } 589 | }).wait(); //Wait for all to finish 590 | } 591 | 592 | void printPrice(json::value const &value){ //temp 593 | if(!value.is_null()){ 594 | json::value test = value; 595 | string v = test["price"].as_string(); 596 | double price = stof(v.c_str()); 597 | servData.inputPrice(price); 598 | // cout << test["price"] << endl << v << endl; 599 | } 600 | 601 | } 602 | 603 | auto binary_to_hex_digit(unsigned a) -> char{ 604 | return a + (a < 10 ? '0' : 'a' - 10); 605 | } 606 | 607 | auto binary_to_hex(unsigned char const* binary, unsigned binary_len) -> string { 608 | string r(binary_len * 2, '\0'); 609 | for(unsigned i = 0; i < binary_len; ++i) { 610 | r[i * 2] = binary_to_hex_digit(binary[i] >> 4); 611 | r[i * 2 + 1] = binary_to_hex_digit(binary[i] & 15); 612 | } 613 | return r; 614 | } 615 | -------------------------------------------------------------------------------- /backTest.h: -------------------------------------------------------------------------------- 1 | #ifndef backTest_h 2 | #define backTest_h 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include //Allows one to see prices of small satoshi's worth coins. 14 | #include //File opens/closes 15 | #include 16 | #include //Boost::erase 17 | #include //abs val 18 | 19 | using namespace utility; // Common utilities like string conversions 20 | using namespace web; // Common features like URIs. 21 | using namespace web::http; // Common HTTP functionality 22 | using namespace web::http::client; // HTTP client features 23 | using namespace concurrency::streams; // Asynchronous streams 24 | using namespace std; 25 | using namespace std::chrono; //Allows us to get epoch time without having to ping Binance server for it 26 | 27 | #define RESTfulHost "https://api.binance.com/" 28 | 29 | class serverData{ 30 | double price; 31 | string pair; 32 | string epochTime; 33 | string signature; //THIS IS THE HMAC SHA256 SIGNATURE. USES MESSAGE AND YOUR SECRET API KEY 34 | string secretKey = "YOUR SECRET KEY HERE"; //THIS IS THE KEY FOR THE HMAC SHA256 35 | string APIKEY = "YOUR KEY HERE"; 36 | public: 37 | void setPair(); 38 | void inputPair(const string input){this->pair = input;} 39 | void setPrice(); 40 | void inputPrice(double foundPrice); 41 | void getTime(); //Get epoch time (It will be needed for the signature) 42 | void HMACsha256(string const&, string const&); 43 | void setSignature(const string sig){this->signature=sig;} 44 | auto getPrice()->double{return this->price;} 45 | auto getPair()->string{return this->pair;} 46 | }servData; 47 | 48 | class backTesting{ 49 | double USDT, BTC=0, LTC=0, ETH=0, BCC=0, BNB=0, NEO=0, ADA=0, QTUM=0, total; 50 | double pastPrice; 51 | public: 52 | void backTest();//temp 53 | void simBuy(); 54 | void simSell(); 55 | void getTotal(); 56 | }backTest; 57 | 58 | class algorithmBot{ 59 | double sellPercent; 60 | bool algoCheck,algoBuy; 61 | public: 62 | void setSellPercent(); 63 | void checkBuy(); 64 | void checkSell(); 65 | void algoBot(); 66 | }algoBot; 67 | 68 | class TechnicalAnalysis{ 69 | vector RSI, stochRSI; 70 | public: 71 | void calcRSI(); 72 | void calcStochRSI(); 73 | auto getRSIback()->long double{return RSI.back();} 74 | }TechnicalAnalysisCalcs; 75 | 76 | class pricingData{ 77 | vector openTime,closeTime,numTrades; 78 | vector open, high, low, close, volume, quoteAssetVolume,takerBuyAssetVol,takerBuyQuoteAssetVol,ignore; 79 | public: 80 | friend class TechnicalAnalysis; 81 | void tradingBot(); 82 | void formatPrice(json::value const &); 83 | void getHistoricalPrices(); 84 | void formatHistoricalPrices(json::value const &); 85 | void clearVecs(); 86 | }priceData; 87 | 88 | #endif /* BinanceBot_h */ 89 | --------------------------------------------------------------------------------