/* WadArchive::getEntryOffset * Returns the file byte offset for [entry] *******************************************************************/ uint32_t WadArchive::getEntryOffset(ArchiveEntry* entry) { // Check entry if (!checkEntry(entry)) return 0; return (uint32_t)(int)entry->exProp("Offset"); }
/* WadArchive::setEntryOffset * Sets the file byte offset for [entry] *******************************************************************/ void WadArchive::setEntryOffset(ArchiveEntry* entry, uint32_t offset) { // Check entry if (!checkEntry(entry)) return; entry->exProp("Offset") = (int)offset; }
void InputMethodManager::load() { FCITX_D(); auto inputMethods = d->addonManager_->addonNames(AddonCategory::InputMethod); auto &path = StandardPath::global(); auto files = path.multiOpenAll(StandardPath::Type::Data, "fcitx5/inputmethod", O_RDONLY, filter::Suffix(".conf")); for (const auto &file : files) { auto &files = file.second; RawConfig config; // reverse the order, so we end up parse user file at last. for (auto iter = files.rbegin(), end = files.rend(); iter != end; iter++) { auto fd = iter->fd(); readFromIni(config, fd); } InputMethodInfo imInfo; imInfo.load(config); InputMethodEntry entry = toInputMethodEntry(imInfo); if (checkEntry(entry, inputMethods) && d->entries_.count(entry.uniqueName()) == 0) { d->entries_.emplace(std::string(entry.uniqueName()), std::move(entry)); } } for (const auto &addonName : inputMethods) { auto addonInfo = d->addonManager_->addonInfo(addonName); // on request input method should always provides entry with config file if (!addonInfo || addonInfo->onRequest()) { continue; } auto engine = static_cast<InputMethodEngine *>(d->addonManager_->addon(addonName)); if (!engine) { continue; } auto newEntries = engine->listInputMethods(); for (auto &newEntry : newEntries) { // ok we can't let you register something werid. if (checkEntry(newEntry, inputMethods) && newEntry.addon() == addonName && d->entries_.count(newEntry.uniqueName()) == 0) { d->entries_.emplace(std::string(newEntry.uniqueName()), std::move(newEntry)); } } } loadConfig(); }
/* GZipArchive::renameEntry * Renames the entry and set the fname flag *******************************************************************/ bool GZipArchive::renameEntry(ArchiveEntry* entry, string name) { // Check entry if (!checkEntry(entry)) return false; // Do default rename bool ok = Archive::renameEntry(entry, name); if (ok) flags |= GZIP_FLG_FNAME; return ok; }
/* Archive::removeEntry * Removes [entry] from the archive. If [delete_entry] is true, the * entry will also be deleted. Returns true if the removal succeeded *******************************************************************/ bool Archive::removeEntry(ArchiveEntry* entry, bool delete_entry) { // Abort if read only if (read_only) return false; // Check entry if (!checkEntry(entry)) return false; // Check if entry is locked if (entry->isLocked()) return false; // Get its directory ArchiveTreeNode* dir = entry->getParentDir(); // Error if entry has no parent directory if (!dir) return false; // Create undo step if (UndoRedo::currentlyRecording()) UndoRedo::currentManager()->recordUndoStep(new EntryCreateDeleteUS(false, entry)); // Get the entry index int index = dir->entryIndex(entry); // Announce (before actually removing in case entry is still needed) MemChunk mc; wxUIntPtr ptr = wxPtrToUInt(entry); mc.write(&index, sizeof(int)); mc.write(&ptr, sizeof(wxUIntPtr)); announce("entry_removing", mc); // Remove it from its directory bool ok = dir->removeEntry(index); // If it was removed ok if (ok) { // Announce removed announce("entry_removed", mc); // Delete if necessary if (delete_entry) delete entry; // Update variables etc setModified(true); } return ok; }
/* RffArchive::renameEntry * Override of Archive::renameEntry to update namespaces if needed * and rename the entry if necessary to be grp-friendly (twelve * characters max) *******************************************************************/ bool RffArchive::renameEntry(ArchiveEntry* entry, string name) { // Check entry if (!checkEntry(entry)) return false; // Process name (must be 12 characters max) name.Truncate(12); if (wad_force_uppercase) name.MakeUpper(); // Do default rename return Archive::renameEntry(entry, name); }
/* Wad2Archive::renameEntry * Override of Archive::renameEntry enforce wad2-friendly entry names * (16 characters max and uppercase if forced) *******************************************************************/ bool Wad2Archive::renameEntry(ArchiveEntry* entry, string name) { // Check entry if (!checkEntry(entry)) return false; // Process name (must be 16 characters max, also cut any extension as wad entries don't usually want them) wxFileName fn(name); name = fn.GetName().Truncate(16); if (wad_force_uppercase) name.MakeUpper(); // Do default rename return Archive::renameEntry(entry, name); }
/* ResArchive::renameEntry * Override of Archive::renameEntry to update namespaces if needed * and rename the entry if necessary to be res-friendly (14 chars max) *******************************************************************/ bool ResArchive::renameEntry(ArchiveEntry* entry, string name) { // Check entry if (!checkEntry(entry)) return false; // Process name (must be 14 characters max) wxFileName fn(name); name = fn.GetName().Truncate(14); // Do default rename return Archive::renameEntry(entry, name); }
/* DatArchive::swapEntries * Override of Archive::swapEntries to update namespaces if needed *******************************************************************/ bool DatArchive::swapEntries(ArchiveEntry* entry1, ArchiveEntry* entry2) { // Check entries if (!checkEntry(entry1) || !checkEntry(entry2)) return false; // Do default swap (force root dir) bool ok = Archive::swapEntries(entry1, entry2); if (ok) { // Update namespaces if needed if (entry1->getName().Upper().Matches("START*") || entry1->getName().Upper().Matches("END*") || entry2->getName().Upper().Matches("START*") || entry2->getName().Upper().Matches("END*")) updateNamespaces(); return true; } else return false; }
// ----------------------------------------------------------------------------- // Override of Archive::renameEntry to update namespaces if needed and rename // the entry if necessary to be grp-friendly (twelve characters max) // ----------------------------------------------------------------------------- bool GrpArchive::renameEntry(ArchiveEntry* entry, const string& name) { // Check entry if (!checkEntry(entry)) return false; // Process name (must be 12 characters max) auto new_name = name; new_name.Truncate(12); if (wad_force_uppercase) new_name.MakeUpper(); // Do default rename return Archive::renameEntry(entry, new_name); }
/* ADatArchive::detectNamespace * Returns the namespace that [entry] is within *******************************************************************/ string ADatArchive::detectNamespace(ArchiveEntry* entry) { // Check entry if (!checkEntry(entry)) return "global"; // If the entry is in the root dir, it's in the global namespace if (entry->getParentDir() == getRoot()) return "global"; // Get the entry's *first* parent directory after root (ie <root>/namespace/) ArchiveTreeNode* dir = entry->getParentDir(); while (dir && dir->getParent() != getRoot()) dir = (ArchiveTreeNode*)dir->getParent(); // Namespace is the directory's name (in lowercase) if (dir) return dir->getName().Lower(); else return "global"; // Error, just return global }
/* DatArchive::moveEntry * Override of Archive::moveEntry to update namespaces if needed *******************************************************************/ bool DatArchive::moveEntry(ArchiveEntry* entry, unsigned position, ArchiveTreeNode* dir) { // Check entry if (!checkEntry(entry)) return false; // Do default move (force root dir) bool ok = Archive::moveEntry(entry, position, NULL); if (ok) { // Update namespaces if necessary if (entry->getName().Upper().Matches("START*") || entry->getName().Upper().Matches("END*")) updateNamespaces(); return true; } else return false; }
/* WadArchive::renameEntry * Override of Archive::renameEntry to update namespaces if needed * and rename the entry if necessary to be wad-friendly (8 characters * max and no file extension) *******************************************************************/ bool WadArchive::renameEntry(ArchiveEntry* entry, string name) { // Check entry if (!checkEntry(entry)) return false; name = processEntryName(name); // Do default rename bool ok = Archive::renameEntry(entry, name); if (ok) { // Update namespaces if necessary if (entry->getName().Upper().Matches("*_START") || entry->getName().Upper().Matches("*_END")) updateNamespaces(); return true; } return false; }
/* DatArchive::renameEntry * Override of Archive::renameEntry to update namespaces if needed *******************************************************************/ bool DatArchive::renameEntry(ArchiveEntry* entry, string name) { // Check entry if (!checkEntry(entry)) return false; // Do default rename bool ok = Archive::renameEntry(entry, name); if (ok) { // Update namespaces if necessary if (entry->getName().Upper().Matches("START*") || entry->getName().Upper().Matches("END*")) updateNamespaces(); return true; } else return false; }
// ----------------------------------------------------------------------------- // Renames [entry] with [name]. // Returns false if the entry was invalid, true otherwise // ----------------------------------------------------------------------------- bool Archive::renameEntry(ArchiveEntry* entry, string_view name) { // Abort if read only if (read_only_) return false; // Check entry if (!checkEntry(entry)) return false; // Check if entry is locked if (entry->isLocked()) return false; // Check for directory if (entry->type() == EntryType::folderType()) return renameDir(dir(entry->path(true)), name); // Announce (before actually renaming in case old name is still needed) MemChunk mc; int index = entryIndex(entry); wxUIntPtr ptr = wxPtrToUInt(entry); mc.write(&index, sizeof(int)); mc.write(&ptr, sizeof(wxUIntPtr)); announce("entry_renaming", mc); // Create undo step if (UndoRedo::currentlyRecording()) UndoRedo::currentManager()->recordUndoStep(std::make_unique<EntryRenameUS>(entry, name)); // Rename the entry entry->setName(name); entry->formatName(formatDesc()); entry->setState(ArchiveEntry::State::Modified, true); // Announce modification entryStateChanged(entry); return true; }
/* Archive::entryStateChanged * Updates the archive variables and announces if necessary that an * entry's state has changed *******************************************************************/ void Archive::entryStateChanged(ArchiveEntry* entry) { // Check the entry is valid and part of this archive if (!checkEntry(entry)) return; // Get the entry index and announce the change MemChunk mc(8); wxUIntPtr ptr = wxPtrToUInt(entry); uint32_t index = entryIndex(entry); mc.write(&index, sizeof(uint32_t)); mc.write(&ptr, sizeof(wxUIntPtr)); announce("entry_state_changed", mc); // If entry was set to unmodified, don't set the archive to modified if (entry->getState() == 0) return; // Set the archive state to modified setModified(true); }
// ----------------------------------------------------------------------------- // Moves [entry] to [position] in [dir]. // If [dir] is null, the root dir is used. // Returns false if the entry was invalid, true otherwise // ----------------------------------------------------------------------------- bool Archive::moveEntry(ArchiveEntry* entry, unsigned position, ArchiveTreeNode* dir) { // Abort if read only if (read_only_) return false; // Check the entry if (!checkEntry(entry)) return false; // Check if the entry is locked if (entry->isLocked()) return false; // Get the entry's current directory auto cdir = entry->parentDir(); // Error if no dir if (!cdir) return false; // If no destination dir specified, use root if (!dir) dir = &dir_root_; // Remove the entry from its current dir auto sptr = dir->sharedEntryAt(dir->entryIndex(entry)); // Get a shared pointer so it isn't deleted removeEntry(entry); // Add it to the destination dir addEntry(entry, position, dir); // Set modified setModified(true); // Return success return true; }
/* Archive::moveEntry * Moves [entry] to [position] in [dir]. If [dir] is NULL, the root * dir is used. Returns false if the entry was invalid, true * otherwise *******************************************************************/ bool Archive::moveEntry(ArchiveEntry* entry, unsigned position, ArchiveTreeNode* dir) { // Abort if read only if (read_only) return false; // Check the entry if (!checkEntry(entry)) return false; // Check if the entry is locked if (entry->isLocked()) return false; // Get the entry's current directory ArchiveTreeNode* cdir = entry->getParentDir(); // Error if no dir if (!cdir) return false; // If no destination dir specified, use root if (!dir) dir = dir_root; // Remove the entry from its current dir removeEntry(entry, false); // Add it to the destination dir addEntry(entry, position, dir); // Set modified setModified(true); // Return success return true; }
/* * Verify that the indirect table lookup is valid. * * Returns "false" if something looks bad. */ bool IndirectRefTable::getChecked(IndirectRef iref) const { if (iref == NULL) { LOGW("Attempt to look up NULL %s reference", indirectRefKindToString(kind_)); return false; } if (indirectRefKind(iref) == kIndirectKindInvalid) { LOGE("JNI ERROR (app bug): invalid %s reference %p", indirectRefKindToString(kind_), iref); abortMaybe(); return false; } int topIndex = segmentState.parts.topIndex; int idx = extractIndex(iref); if (idx >= topIndex) { /* bad -- stale reference? */ LOGE("JNI ERROR (app bug): accessed stale %s reference %p (index %d in a table of size %d)", indirectRefKindToString(kind_), iref, idx, topIndex); abortMaybe(); return false; } if (table_[idx] == NULL) { LOGI("JNI ERROR (app bug): accessed deleted %s reference %p", indirectRefKindToString(kind_), iref); abortMaybe(); return false; } if (!checkEntry("use", iref, idx)) { return false; } return true; }
/* DatArchive::removeEntry * Override of Archive::removeEntry to update namespaces if needed *******************************************************************/ bool DatArchive::removeEntry(ArchiveEntry* entry, bool delete_entry) { // Check entry if (!checkEntry(entry)) return false; // Get entry name (for later) string name = entry->getName(); // Do default remove bool ok = Archive::removeEntry(entry, delete_entry); if (ok) { // Update namespaces if necessary if (name.Upper().Matches("START*") || name.Upper().Matches("END*")) updateNamespaces(); return true; } else return false; }
/* ZipArchive::getMapInfo * Returns the mapdesc_t information about the map at [entry], if * [entry] is actually a valid map (ie. a wad archive in the maps * folder) *******************************************************************/ Archive::mapdesc_t ZipArchive::getMapInfo(ArchiveEntry* entry) { mapdesc_t map; // Check entry if (!checkEntry(entry)) return map; // Check entry type if (entry->getType()->getFormat() != "archive_wad") return map; // Check entry directory if (entry->getParentDir()->getParent() != getRoot() || entry->getParentDir()->getName() != "maps") return map; // Setup map info map.archive = true; map.head = entry; map.end = entry; map.name = entry->getName(true).Upper(); return map; }
int main(int argc, char** argv) { std::cout << "Blackbird Bitcoin Arbitrage" << std::endl; std::cout << "DISCLAIMER: USE THE SOFTWARE AT YOUR OWN RISK\n" << std::endl; std::locale mylocale(""); Parameters params("blackbird.conf"); if (!params.demoMode) { if (!params.useFullCash) { if (params.cashForTesting < 10.0) { std::cout << "WARNING: Minimum test cash recommended: $10.00\n" << std::endl; } if (params.cashForTesting > params.maxExposure) { std::cout << "ERROR: Test cash ($" << params.cashForTesting << ") is above max exposure ($" << params.maxExposure << ")\n" << std::endl; return -1; } } } getQuoteType getQuote[10]; getAvailType getAvail[10]; sendOrderType sendOrder[10]; isOrderCompleteType isOrderComplete[10]; getActivePosType getActivePos[10]; getLimitPriceType getLimitPrice[10]; int index = 0; if (params.bitfinexApi.empty() == false || params.demoMode == true) { params.addExchange("Bitfinex", params.bitfinexFees, params.bitfinexCanShort, true); getQuote[index] = Bitfinex::getQuote; getAvail[index] = Bitfinex::getAvail; sendOrder[index] = Bitfinex::sendOrder; isOrderComplete[index] = Bitfinex::isOrderComplete; getActivePos[index] = Bitfinex::getActivePos; getLimitPrice[index] = Bitfinex::getLimitPrice; index++; } if (params.okcoinApi.empty() == false || params.demoMode == true) { params.addExchange("OKCoin", params.okcoinFees, params.okcoinCanShort, true); getQuote[index] = OkCoin::getQuote; getAvail[index] = OkCoin::getAvail; sendOrder[index] = OkCoin::sendOrder; isOrderComplete[index] = OkCoin::isOrderComplete; getActivePos[index] = OkCoin::getActivePos; getLimitPrice[index] = OkCoin::getLimitPrice; index++; } if (params.bitstampClientId.empty() == false || params.demoMode == true) { params.addExchange("Bitstamp", params.bitstampFees, params.bitstampCanShort, true); getQuote[index] = Bitstamp::getQuote; getAvail[index] = Bitstamp::getAvail; sendOrder[index] = Bitstamp::sendOrder; isOrderComplete[index] = Bitstamp::isOrderComplete; getActivePos[index] = Bitstamp::getActivePos; getLimitPrice[index] = Bitstamp::getLimitPrice; index++; } if (params.geminiApi.empty() == false || params.demoMode == true) { params.addExchange("Gemini", params.geminiFees, params.geminiCanShort, true); getQuote[index] = Gemini::getQuote; getAvail[index] = Gemini::getAvail; sendOrder[index] = Gemini::sendOrder; isOrderComplete[index] = Gemini::isOrderComplete; getActivePos[index] = Gemini::getActivePos; getLimitPrice[index] = Gemini::getLimitPrice; index++; } if (params.krakenApi.empty() == false || params.demoMode == true) { params.addExchange("Kraken", params.krakenFees, params.krakenCanShort, true); getQuote[index] = Kraken::getQuote; getAvail[index] = Kraken::getAvail; sendOrder[index] = Kraken::sendOrder; isOrderComplete[index] = Kraken::isOrderComplete; getActivePos[index] = Kraken::getActivePos; getLimitPrice[index] = Kraken::getLimitPrice; index++; } if (params.itbitApi.empty() == false || params.demoMode == true) { params.addExchange("ItBit", params.itbitFees, params.itbitCanShort, false); getQuote[index] = ItBit::getQuote; getAvail[index] = ItBit::getAvail; // sendOrder[index] = ItBit::sendOrder; // isOrderComplete[index] = ItBit::isOrderComplete; getActivePos[index] = ItBit::getActivePos; getLimitPrice[index] = ItBit::getLimitPrice; index++; } if (params.btceApi.empty() == false || params.demoMode == true) { params.addExchange("BTC-e", params.btceFees, params.btceCanShort, false); getQuote[index] = BTCe::getQuote; getAvail[index] = BTCe::getAvail; // sendOrder[index] = BTCe::sendOrder; // isOrderComplete[index] = BTCe::isOrderComplete; getActivePos[index] = BTCe::getActivePos; getLimitPrice[index] = BTCe::getLimitPrice; index++; } if (params.sevennintysixApi.empty() == false || params.demoMode == true) { params.addExchange("796.com", params.sevennintysixFees, params.sevennintysixCanShort, true); getQuote[index] = SevenNintySix::getQuote; getAvail[index] = SevenNintySix::getAvail; sendOrder[index] = SevenNintySix::sendOrder; isOrderComplete[index] = SevenNintySix::isOrderComplete; getActivePos[index] = SevenNintySix::getActivePos; getLimitPrice[index] = SevenNintySix::getLimitPrice; index++; } if (index < 2) { std::cout << "ERROR: Blackbird needs at least two Bitcoin exchanges. Please edit the config.json file to add new exchanges\n" << std::endl; return -1; } std::string currDateTime = printDateTimeFileName(); std::string csvFileName = "blackbird_result_" + currDateTime + ".csv"; std::ofstream csvFile; csvFile.open(csvFileName.c_str(), std::ofstream::trunc); csvFile << "TRADE_ID,EXCHANGE_LONG,EXHANGE_SHORT,ENTRY_TIME,EXIT_TIME,DURATION,TOTAL_EXPOSURE,BALANCE_BEFORE,BALANCE_AFTER,RETURN\n"; csvFile.flush(); std::string logFileName = "blackbird_log_" + currDateTime + ".log"; std::ofstream logFile; logFile.open(logFileName.c_str(), std::ofstream::trunc); logFile.imbue(mylocale); logFile.precision(2); logFile << std::fixed; params.logFile = &logFile; logFile << "--------------------------------------------" << std::endl; logFile << "| Blackbird Bitcoin Arbitrage Log File |" << std::endl; logFile << "--------------------------------------------\n" << std::endl; logFile << "Blackbird started on " << printDateTime() << "\n" << std::endl; if (params.demoMode) { logFile << "Demo mode: trades won't be generated\n" << std::endl; } std::cout << "Log file generated: " << logFileName << "\nBlackbird is running... (pid " << getpid() << ")\n" << std::endl; // Vector of Bitcoin objects std::vector<Bitcoin*> btcVec; int num_exchange = params.nbExch(); // create Bitcoin objects for (int i = 0; i < num_exchange; ++i) { btcVec.push_back(new Bitcoin(i, params.exchName[i], params.fees[i], params.canShort[i], params.isImplemented[i])); } curl_global_init(CURL_GLOBAL_ALL); params.curl = curl_easy_init(); logFile << "[ Targets ]" << std::endl; logFile << " Spread Entry: " << params.spreadEntry * 100.0 << "%" << std::endl; logFile << " Spread Target: " << params.spreadTarget * 100.0 << "%" << std::endl; if (params.spreadEntry <= 0.0) { logFile << " WARNING: Spread Entry should be positive" << std::endl; } if (params.spreadTarget <= 0.0) { logFile << " WARNING: Spread Target should be positive" << std::endl; } logFile << std::endl; // store current balances logFile << "[ Current balances ]" << std::endl; double* balanceUsd = (double*)malloc(sizeof(double) * num_exchange); double* balanceBtc = (double*)malloc(sizeof(double) * num_exchange); for (int i = 0; i < num_exchange; ++i) { if (params.demoMode) { balanceUsd[i] = 0.0; balanceBtc[i] = 0.0; } else { balanceUsd[i] = getAvail[i](params, "usd"); balanceBtc[i] = getAvail[i](params, "btc"); } } // contains balances after a completed trade double* newBalUsd = (double*)malloc(sizeof(double) * num_exchange); double* newBalBtc = (double*)malloc(sizeof(double) * num_exchange); memset(newBalUsd, 0.0, sizeof(double) * num_exchange); memset(newBalBtc, 0.0, sizeof(double) * num_exchange); for (int i = 0; i < num_exchange; ++i) { logFile << " " << params.exchName[i] << ":\t"; logFile << balanceUsd[i] << " USD\t" << std::setprecision(6) << balanceBtc[i] << std::setprecision(2) << " BTC" << std::endl; if (balanceBtc[i] > 0.0300) { logFile << "ERROR: All BTC accounts must be empty before starting Blackbird" << std::endl; return -1; } } logFile << std::endl; logFile << "[ Cash exposure ]" << std::endl; if (params.demoMode) { logFile << " No cash - Demo mode" << std::endl; } else { if (params.useFullCash) { logFile << " FULL cash used!" << std::endl; } else { logFile << " TEST cash used\n Value: $" << params.cashForTesting << std::endl; } } logFile << std::endl; time_t rawtime; rawtime = time(NULL); struct tm* timeinfo; timeinfo = localtime(&rawtime); // wait the next gapSec seconds before starting time(&rawtime); timeinfo = localtime(&rawtime); while ((int)timeinfo->tm_sec % params.gapSec != 0) { sleep(0.01); time(&rawtime); timeinfo = localtime(&rawtime); } // main loop if (!params.verbose) { logFile << "Running..." << std::endl; } bool inMarket = false; int resultId = 0; Result res; res.clear(); unsigned currIteration = 0; bool stillRunning = true; time_t currTime; time_t diffTime; while (stillRunning) { currTime = mktime(timeinfo); time(&rawtime); diffTime = difftime(rawtime, currTime); // check if we are already too late if (diffTime > 0) { logFile << "WARNING: " << diffTime << " second(s) too late at " << printDateTime(currTime) << std::endl; // unsigned skip = (unsigned)ceil(diffTime / gapSec); // go to next iteration timeinfo->tm_sec = timeinfo->tm_sec + (ceil(diffTime / params.gapSec) + 1) * params.gapSec; currTime = mktime(timeinfo); sleep(params.gapSec - (diffTime % params.gapSec)); logFile << std::endl; } else if (diffTime < 0) { sleep(-difftime(rawtime, currTime)); // sleep until the next iteration } if (params.verbose) { if (!inMarket) { logFile << "[ " << printDateTime(currTime) << " ]" << std::endl; } else { logFile << "[ " << printDateTime(currTime) << " IN MARKET: Long " << res.exchNameLong << " / Short " << res.exchNameShort << " ]" << std::endl; } } for (int e = 0; e < num_exchange; ++e) { double bid = getQuote[e](params, true); double ask = getQuote[e](params, false); if (bid == 0.0) { logFile << " WARNING: " << params.exchName[e] << " bid is null, use previous one" << std::endl; } if (ask == 0.0) { logFile << " WARNING: " << params.exchName[e] << " ask is null, use previous one" << std::endl; } if (params.verbose) { logFile << " " << params.exchName[e] << ": \t" << bid << " / " << ask << std::endl; } btcVec[e]->updateData(bid, ask, 0.0); curl_easy_reset(params.curl); } if (params.verbose) { logFile << " ----------------------------" << std::endl; } // compute entry point if (!inMarket) { for (int i = 0; i < num_exchange; ++i) { for (int j = 0; j < num_exchange; ++j) { if (i != j) { if (checkEntry(btcVec[i], btcVec[j], res, params)) { // entry opportunity found res.exposure = std::min(balanceUsd[res.idExchLong], balanceUsd[res.idExchShort]); if (params.demoMode) { logFile << "INFO: Opportunity found but no trade will be generated (Demo mode)" << std::endl; break; } if (res.exposure == 0.0) { logFile << "WARNING: Opportunity found but no cash available. Trade canceled" << std::endl; break; } if (params.useFullCash == false && res.exposure <= params.cashForTesting) { logFile << "WARNING: Opportunity found but no enough cash. Need more than TEST cash (min. $" << params.cashForTesting << "). Trade canceled" << std::endl; break; } if (params.useFullCash) { res.exposure -= params.untouchedCash * res.exposure; // leave untouchedCash if (res.exposure > params.maxExposure) { logFile << "WARNING: Opportunity found but exposure ($" << res.exposure << ") above the limit" << std::endl; logFile << " Max exposure will be used instead ($" << params.maxExposure << ")" << std::endl; res.exposure = params.maxExposure; } } else { res.exposure = params.cashForTesting; // use test money } double volumeLong = res.exposure / btcVec[res.idExchLong]->getAsk(); double volumeShort = res.exposure / btcVec[res.idExchShort]->getBid(); double limPriceLong = getLimitPrice[res.idExchLong](params, volumeLong, false); double limPriceShort = getLimitPrice[res.idExchShort](params, volumeShort, true); if (limPriceLong - res.priceLongIn > params.priceDeltaLim || res.priceShortIn - limPriceShort > params.priceDeltaLim) { logFile << "WARNING: Opportunity found but not enough liquidity. Trade canceled" << std::endl; logFile << " Target long price: " << res.priceLongIn << ", Real long price: " << limPriceLong << std::endl; logFile << " Target short price: " << res.priceShortIn << ", Real short price: " << limPriceShort << std::endl; res.trailing[res.idExchLong][res.idExchShort] = -1.0; break; } inMarket = true; resultId++; // update result res.id = resultId; res.entryTime = currTime; res.printEntry(*params.logFile); res.maxSpread[res.idExchLong][res.idExchShort] = -1.0; res.minSpread[res.idExchLong][res.idExchShort] = 1.0; res.trailing[res.idExchLong][res.idExchShort] = 1.0; int longOrderId = 0; int shortOrderId = 0; // send orders longOrderId = sendOrder[res.idExchLong](params, "buy", volumeLong, btcVec[res.idExchLong]->getAsk()); shortOrderId = sendOrder[res.idExchShort](params, "sell", volumeShort, btcVec[res.idExchShort]->getBid()); // wait for the orders to be filled logFile << "Waiting for the two orders to be filled..." << std::endl; sleep(3.0); while (!isOrderComplete[res.idExchLong](params, longOrderId) || !isOrderComplete[res.idExchShort](params, shortOrderId)) { sleep(3.0); } logFile << "Done" << std::endl; longOrderId = 0; shortOrderId = 0; break; } } } if (inMarket) { break; } } if (params.verbose) { logFile << std::endl; } } // in market, looking to exit else if (inMarket) { if (checkExit(btcVec[res.idExchLong], btcVec[res.idExchShort], res, params, currTime)) { // exit opportunity found // check current exposure double* btcUsed = (double*)malloc(sizeof(double) * num_exchange); for (int i = 0; i < num_exchange; ++i) { btcUsed[i] = getActivePos[i](params); } double volumeLong = btcUsed[res.idExchLong]; double volumeShort = btcUsed[res.idExchShort]; double limPriceLong = getLimitPrice[res.idExchLong](params, volumeLong, true); double limPriceShort = getLimitPrice[res.idExchShort](params, volumeShort, false); if (res.priceLongOut - limPriceLong > params.priceDeltaLim || limPriceShort - res.priceShortOut > params.priceDeltaLim) { logFile << "WARNING: Opportunity found but not enough liquidity. Trade canceled" << std::endl; logFile << " Target long price: " << res.priceLongOut << ", Real long price: " << limPriceLong << std::endl; logFile << " Target short price: " << res.priceShortOut << ", Real short price: " << limPriceShort << std::endl; res.trailing[res.idExchLong][res.idExchShort] = 1.0; } else { res.exitTime = currTime; res.printExit(*params.logFile); int longOrderId = 0; int shortOrderId = 0; logFile << std::setprecision(6) << "BTC exposure on " << params.exchName[res.idExchLong] << ": " << volumeLong << std::setprecision(2) << std::endl; logFile << std::setprecision(6) << "BTC exposure on " << params.exchName[res.idExchShort] << ": " << volumeShort << std::setprecision(2) << std::endl; logFile << std::endl; // send orders longOrderId = sendOrder[res.idExchLong](params, "sell", fabs(btcUsed[res.idExchLong]), btcVec[res.idExchLong]->getBid()); shortOrderId = sendOrder[res.idExchShort](params, "buy", fabs(btcUsed[res.idExchShort]), btcVec[res.idExchShort]->getAsk()); // wait for the orders to be filled logFile << "Waiting for the two orders to be filled..." << std::endl; sleep(3.0); while (!isOrderComplete[res.idExchLong](params, longOrderId) || !isOrderComplete[res.idExchShort](params, shortOrderId)) { sleep(3.0); } logFile << "Done\n" << std::endl; longOrderId = 0; shortOrderId = 0; inMarket = false; // new balances for (int i = 0; i < num_exchange; ++i) { newBalUsd[i] = getAvail[i](params, "usd"); newBalBtc[i] = getAvail[i](params, "btc"); } for (int i = 0; i < num_exchange; ++i) { logFile << "New balance on " << params.exchName[i] << ": \t"; logFile << newBalUsd[i] << " USD (perf $" << newBalUsd[i] - balanceUsd[i] << "), "; logFile << std::setprecision(6) << newBalBtc[i] << std::setprecision(2) << " BTC" << std::endl; } logFile << std::endl; // update res with total balance for (int i = 0; i < num_exchange; ++i) { res.befBalUsd += balanceUsd[i]; res.aftBalUsd += newBalUsd[i]; } // update current balances with new values for (int i = 0; i < num_exchange; ++i) { balanceUsd[i] = newBalUsd[i]; balanceBtc[i] = newBalBtc[i]; } logFile << "ACTUAL PERFORMANCE: " << "$" << res.aftBalUsd - res.befBalUsd << " (" << res.totPerf() * 100.0 << "%)\n" << std::endl; csvFile << res.id << "," << res.exchNameLong << "," << res.exchNameShort << "," << printDateTimeCsv(res.entryTime) << "," << printDateTimeCsv(res.exitTime); csvFile << "," << res.getLength() << "," << res.exposure * 2.0 << "," << res.befBalUsd << "," << res.aftBalUsd << "," << res.totPerf() << "\n"; csvFile.flush(); if (params.sendEmail) { sendEmail(res, params); logFile << "Email sent" << std::endl; } res.clear(); std::ifstream infile("stop_after_exit"); if (infile.good()) { logFile << "Exit after last trade (file stop_after_exit found)" << std::endl; stillRunning = false; } } } if (params.verbose) { logFile << std::endl; } } timeinfo->tm_sec = timeinfo->tm_sec + params.gapSec; currIteration++; if (currIteration >= params.debugMaxIteration) { logFile << "Max iteration reached (" << params.debugMaxIteration << ")" <<std::endl; stillRunning = false; } } for (int i = 0; i < num_exchange; ++i) { delete(btcVec[i]); } curl_easy_cleanup(params.curl); curl_global_cleanup(); csvFile.close(); logFile.close(); return 0; }
DvbEpgDialog::DvbEpgDialog(DvbManager *manager_, QWidget *parent) : KDialog(parent), manager(manager_) { setButtons(KDialog::Close); setCaption(i18nc("@title:window", "Program Guide")); QWidget *widget = new QWidget(this); QBoxLayout *mainLayout = new QHBoxLayout(widget); epgChannelTableModel = new DvbEpgChannelTableModel(this); epgChannelTableModel->setManager(manager); channelView = new QTreeView(widget); channelView->setMaximumWidth(30 * fontMetrics().averageCharWidth()); channelView->setModel(epgChannelTableModel); channelView->setRootIsDecorated(false); channelView->setUniformRowHeights(true); connect(channelView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(channelActivated(QModelIndex))); mainLayout->addWidget(channelView); QBoxLayout *rightLayout = new QVBoxLayout(); QBoxLayout *boxLayout = new QHBoxLayout(); KAction *scheduleAction = new KAction(QIcon::fromTheme(QLatin1String("media-record")), i18nc("@action:inmenu tv show", "Record Show"), this); connect(scheduleAction, SIGNAL(triggered()), this, SLOT(scheduleProgram())); QPushButton *pushButton = new QPushButton(scheduleAction->icon(), scheduleAction->text(), widget); connect(pushButton, SIGNAL(clicked()), this, SLOT(scheduleProgram())); boxLayout->addWidget(pushButton); boxLayout->addWidget(new QLabel(i18nc("@label:textbox", "Search:"), widget)); epgTableModel = new DvbEpgTableModel(this); epgTableModel->setEpgModel(manager->getEpgModel()); connect(epgTableModel, SIGNAL(layoutChanged()), this, SLOT(checkEntry())); KLineEdit *lineEdit = new KLineEdit(widget); lineEdit->setClearButtonShown(true); connect(lineEdit, SIGNAL(textChanged(QString)), epgTableModel, SLOT(setContentFilter(QString))); boxLayout->addWidget(lineEdit); rightLayout->addLayout(boxLayout); epgView = new QTreeView(widget); epgView->addAction(scheduleAction); epgView->header()->setResizeMode(QHeaderView::ResizeToContents); epgView->setContextMenuPolicy(Qt::ActionsContextMenu); epgView->setMinimumWidth(75 * fontMetrics().averageCharWidth()); epgView->setModel(epgTableModel); epgView->setRootIsDecorated(false); epgView->setUniformRowHeights(true); connect(epgView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(entryActivated(QModelIndex))); rightLayout->addWidget(epgView); contentLabel = new QLabel(widget); contentLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop); contentLabel->setMargin(5); contentLabel->setWordWrap(true); QScrollArea *scrollArea = new QScrollArea(widget); scrollArea->setBackgroundRole(QPalette::Light); scrollArea->setMinimumHeight(12 * fontMetrics().height()); scrollArea->setWidget(contentLabel); scrollArea->setWidgetResizable(true); rightLayout->addWidget(scrollArea); mainLayout->addLayout(rightLayout); setMainWidget(widget); }
int main(int argc, char **argv) { // header information std::cout << "Blackbird Bitcoin Arbitrage\nVersion 0.0.2" << std::endl; std::cout << "DISCLAIMER: USE THE SOFTWARE AT YOUR OWN RISK.\n" << std::endl; // read the config file (config.json) json_error_t error; json_t *root = json_load_file("config.json", 0, &error); if (!root) { std::cout << "ERROR: config.json incorrect (" << error.text << ")\n" << std::endl; return 1; } // get config variables int gapSec = json_integer_value(json_object_get(root, "GapSec")); unsigned debugMaxIteration = json_integer_value(json_object_get(root, "DebugMaxIteration")); bool useFullCash = json_boolean_value(json_object_get(root, "UseFullCash")); double untouchedCash = json_real_value(json_object_get(root, "UntouchedCash")); double cashForTesting = json_real_value(json_object_get(root, "CashForTesting")); if (!useFullCash && cashForTesting < 15.0) { std::cout << "ERROR: Minimum test cash is $15.00.\n" << std::endl; return 1; } // function arrays getQuoteType getQuote[] = {Bitfinex::getQuote, OkCoin::getQuote, Bitstamp::getQuote, Kraken::getQuote}; getAvailType getAvail[] = {Bitfinex::getAvail, OkCoin::getAvail, Bitstamp::getAvail, Kraken::getAvail}; sendOrderType sendOrder[] = {Bitfinex::sendOrder, OkCoin::sendOrder, Bitstamp::sendOrder}; isOrderCompleteType isOrderComplete[] = {Bitfinex::isOrderComplete, OkCoin::isOrderComplete, Bitstamp::isOrderComplete}; getActivePosType getActivePos[] = {Bitfinex::getActivePos, OkCoin::getActivePos, Bitstamp::getActivePos, Kraken::getActivePos}; getLimitPriceType getLimitPrice[] = {Bitfinex::getLimitPrice, OkCoin::getLimitPrice, Bitstamp::getLimitPrice, Kraken::getLimitPrice}; // thousand separator std::locale mylocale(""); std::cout.imbue(mylocale); // print precision of two digits std::cout.precision(2); std::cout << std::fixed; // create a parameters structure Parameters params(root); params.addExchange("Bitfinex", 0.0020, true); params.addExchange("OKCoin", 0.0020, false); params.addExchange("Bitstamp", 0.0025, false); params.addExchange("Kraken", 0.0025, true); // CSV file std::string csvFileName; csvFileName = "result_" + printDateTimeFileName() + ".csv"; std::ofstream csvFile; csvFile.open(csvFileName.c_str(), std::ofstream::trunc); // CSV header csvFile << "TRADE_ID,EXCHANGE_LONG,EXHANGE_SHORT,ENTRY_TIME,EXIT_TIME,DURATION,TOTAL_EXPOSURE,BALANCE_BEFORE,BALANCE_AFTER,RETURN\n"; csvFile.flush(); // time structure time_t rawtime; rawtime = time(NULL); struct tm * timeinfo; timeinfo = localtime(&rawtime); bool inMarket = false; int resultId = 0; Result res; res.clear(); // Vector of Bitcoin std::vector<Bitcoin*> btcVec; // create Bitcoin objects for (unsigned i = 0; i < params.nbExch(); ++i) { btcVec.push_back(new Bitcoin(i, params.exchName[i], params.fees[i], params.hasShort[i])); } // cURL CURL* curl; curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); std::cout << "[ Targets ]" << std::endl; std::cout << " Spread to enter: " << params.spreadEntry * 100.0 << "%" << std::endl; std::cout << " Spread to exit: " << params.spreadExit * 100.0 << "%" << std::endl; std::cout << std::endl; // store current balances std::cout << "[ Current balances ]" << std::endl; std::vector<double> balanceUsd; std::vector<double> balanceBtc; for (unsigned i = 0; i < params.nbExch(); ++i) { balanceUsd.push_back(getAvail[i](curl, params, "usd")); balanceBtc.push_back(getAvail[i](curl, params, "btc")); } // vectors that contains balances after a completed trade std::vector<double> newBalUsd(params.nbExch(), 0.0); std::vector<double> newBalBtc(params.nbExch(), 0.0); for (unsigned i = 0; i < params.nbExch(); ++i) { std::cout << " " << params.exchName[i] << ":\t"; std::cout << balanceUsd[i] << " USD\t" << std::setprecision(6) << balanceBtc[i] << std::setprecision(2) << " BTC" << std::endl; } std::cout << std::endl; std::cout << "[ Cash exposure ]" << std::endl; if (useFullCash) { std::cout << " FULL cash used!" << std::endl; } else { std::cout << " TEST cash used\n Value: $" << cashForTesting << std::endl; } std::cout << std::endl; // wait the next gapSec seconds before starting time(&rawtime); timeinfo = localtime(&rawtime); while ((int)timeinfo->tm_sec % gapSec != 0) { sleep(0.01); time(&rawtime); timeinfo = localtime(&rawtime); } // main loop if (!params.verbose) { std::cout << "Running..." << std::endl; } unsigned currIteration = 0; bool stillRunning = true; while (stillRunning) { time_t currTime = mktime(timeinfo); time(&rawtime); // check if we are already too late if (difftime(rawtime, currTime) > 0) { std::cout << "WARNING: " << difftime(rawtime, currTime) << " second(s) too late at " << printDateTime(currTime) << std::endl; unsigned skip = (unsigned)ceil(difftime(rawtime, currTime) / gapSec); for (unsigned i = 0; i < skip; ++i) { // std::cout << " Skipped iteration " << printDateTime(currTime) << std::endl; for (unsigned e = 0; e < params.nbExch(); ++e) { btcVec[e]->addData(currTime, btcVec[e]->getLastBid(), btcVec[e]->getLastAsk(), 0.0); } // go to next iteration timeinfo->tm_sec = timeinfo->tm_sec + gapSec; currTime = mktime(timeinfo); } std::cout << std::endl; } // wait for the next iteration while (difftime(rawtime, currTime) != 0) { sleep(0.01); time(&rawtime); } if (params.verbose) { if (!inMarket) { std::cout << "[ " << printDateTime(currTime) << " ]" << std::endl; } else { std::cout << "[ " << printDateTime(currTime) << " IN MARKET: Long " << res.exchNameLong << " / Short " << res.exchNameShort << " ]" << std::endl; } } // download the exchanges prices for (unsigned e = 0; e < params.nbExch(); ++e) { double bid = getQuote[e](curl, true); double ask = getQuote[e](curl, false); // add previous price if bid or ask is 0.0 if (bid == 0.0) { bid = btcVec[e]->getLastBid(); std::cout << " WARNING: " << params.exchName[e] << " bid is null, use previous one" << std::endl; } if (ask == 0.0) { ask = btcVec[e]->getLastAsk(); std::cout << " WARNING: " << params.exchName[e] << " ask is null, use previous one" << std::endl; } if (params.verbose) { std::cout << " " << params.exchName[e] << ": \t" << bid << " / " << ask << std::endl; } btcVec[e]->addData(currTime, bid, ask, 0.0); curl_easy_reset(curl); } // load data terminated if (params.verbose) { std::cout << " ----------------------------" << std::endl; } // compute entry point if (!inMarket) { for (unsigned i = 0; i < params.nbExch(); ++i) { for (unsigned j = 0; j < params.nbExch(); ++j) { if (i != j) { if (checkEntry(btcVec[i], btcVec[j], res, params)) { // entry opportunity found // compute exposure res.exposure = std::min(balanceUsd[res.idExchLong], balanceUsd[res.idExchShort]); if (res.exposure == 0.0) { std::cout << " WARNING: Opportunity found but no cash available. Trade canceled." << std::endl; break; } if (useFullCash == false && res.exposure <= cashForTesting) { std::cout << " WARNING: Opportunity found but no enough cash. Need more than TEST cash (min. $" << cashForTesting << "). Trade canceled." << std::endl; break; } if (useFullCash) { // leave untouchedCash res.exposure -= untouchedCash * res.exposure; } else { // use test money res.exposure = cashForTesting; } // check volumes double volumeLong = res.exposure / btcVec[res.idExchLong]->getLastAsk(); double volumeShort = res.exposure / btcVec[res.idExchShort]->getLastBid(); double limPriceLong = getLimitPrice[res.idExchLong](curl, volumeLong, false); double limPriceShort = getLimitPrice[res.idExchShort](curl, volumeShort, true); if (limPriceLong - res.priceLongIn > 0.30 || res.priceShortIn - limPriceShort > 0.30) { std::cout << " WARNING: Opportunity found but not enough volume. Trade canceled." << std::endl; break; } inMarket = true; resultId++; // update result res.id = resultId; res.entryTime = currTime; res.printEntry(); res.maxSpread[res.idExchLong][res.idExchShort] = -1.0; res.minSpread[res.idExchLong][res.idExchShort] = 1.0; int longOrderId = 0; int shortOrderId = 0; // send Long order longOrderId = sendOrder[res.idExchLong](curl, params, "buy", volumeLong, btcVec[res.idExchLong]->getLastAsk()); // send Short order shortOrderId = sendOrder[res.idExchShort](curl, params, "sell", volumeShort, btcVec[res.idExchShort]->getLastBid()); // wait for the orders to be filled sleep(3.0); std::cout << "Waiting for the two orders to be filled..." << std::endl; while (!isOrderComplete[res.idExchLong](curl, params, longOrderId) || !isOrderComplete[res.idExchShort](curl, params, shortOrderId)) { sleep(3.0); } std::cout << "Done" << std::endl; longOrderId = 0; shortOrderId = 0; break; } } } if (inMarket) { break; } } if (params.verbose) { std::cout << std::endl; } } // in market, looking to exit else if (inMarket) { if (checkExit(btcVec[res.idExchLong], btcVec[res.idExchShort], res, params, currTime)) { // exit opportunity found // check current exposure std::vector<double> btcUsed; for (unsigned i = 0; i < params.nbExch(); ++i) { btcUsed.push_back(getActivePos[i](curl, params)); } // check volumes double volumeLong = btcUsed[res.idExchLong]; double volumeShort = btcUsed[res.idExchShort]; double limPriceLong = getLimitPrice[res.idExchLong](curl, volumeLong, true); double limPriceShort = getLimitPrice[res.idExchShort](curl, volumeShort, false); if (res.priceLongOut - limPriceLong > 0.30 || limPriceShort - res.priceShortOut > 0.30) { std::cout << " WARNING: Opportunity found but not enough volume. Trade canceled." << std::endl; } else { res.exitTime = currTime; res.printExit(); // send orders int longOrderId = 0; int shortOrderId = 0; std::cout << std::setprecision(6) << "BTC exposure on " << params.exchName[res.idExchLong] << ": " << volumeLong << std::setprecision(2) << std::endl; std::cout << std::setprecision(6) << "BTC exposure on " << params.exchName[res.idExchShort] << ": " << volumeShort << std::setprecision(2) << std::endl; std::cout << std::endl; // Close Long longOrderId = sendOrder[res.idExchLong](curl, params, "sell", fabs(btcUsed[res.idExchLong]), btcVec[res.idExchLong]->getLastBid()); // Close Short shortOrderId = sendOrder[res.idExchShort](curl, params, "buy", fabs(btcUsed[res.idExchShort]), btcVec[res.idExchShort]->getLastAsk()); // wait for the orders to be filled sleep(3.0); std::cout << "Waiting for the two orders to be filled..." << std::endl; while (!isOrderComplete[res.idExchLong](curl, params, longOrderId) || !isOrderComplete[res.idExchShort](curl, params, shortOrderId)) { sleep(3.0); } std::cout << "Done\n" << std::endl; longOrderId = 0; shortOrderId = 0; // market exited inMarket = false; // new balances for (unsigned i = 0; i < params.nbExch(); ++i) { newBalUsd[i] = getAvail[i](curl, params, "usd"); newBalBtc[i] = getAvail[i](curl, params, "btc"); } for (unsigned i = 0; i < params.nbExch(); ++i) { std::cout << "New balance on " << params.exchName[i] << ": \t"; std::cout << newBalUsd[i] << " USD (perf $" << newBalUsd[i] - balanceUsd[i] << "), "; std::cout << std::setprecision(6) << newBalBtc[i] << std::setprecision(2) << " BTC" << std::endl; } std::cout << std::endl; // update res with total balance res.befBalUsd = std::accumulate(balanceUsd.begin(), balanceUsd.end(), 0.0); res.aftBalUsd = std::accumulate(newBalUsd.begin(), newBalUsd.end(), 0.0); // update current balances with new values for (unsigned i = 0; i < params.nbExch(); ++i) { balanceUsd[i] = newBalUsd[i]; balanceBtc[i] = newBalBtc[i]; } // display performance std::cout << "ACTUAL PERFORMANCE: " << "$" << res.aftBalUsd - res.befBalUsd << " (" << res.totPerf() * 100.0 << "%)\n" << std::endl; // new csv line with result csvFile << res.id << "," << res.exchNameLong << "," << res.exchNameShort << "," << printDateTimeCsv(res.entryTime) << "," << printDateTimeCsv(res.exitTime); csvFile << "," << res.getLength() << "," << res.exposure * 2.0 << "," << res.befBalUsd << "," << res.aftBalUsd << "," << res.totPerf() << "\n"; csvFile.flush(); // send email if (params.sendEmail) { sendEmail(res, params); std::cout << "Email sent" << std::endl; } // delete result information res.clear(); // if "stop_after_exit" file exists then return std::ifstream infile("stop_after_exit"); if (infile.good()) { std::cout << "Exit after last trade (file stop_after_exit found)" << std::endl; stillRunning = false; } } } if (params.verbose) { std::cout << std::endl; } } // activities for this iteration terminated timeinfo->tm_sec = timeinfo->tm_sec + gapSec; currIteration++; if (currIteration >= debugMaxIteration) { std::cout << "Max iteration reached (" << debugMaxIteration << ")" <<std::endl; stillRunning = false; } } // delete Bitcoin objects for (unsigned i = 0; i < params.nbExch(); ++i) { delete(btcVec[i]); } json_decref(root); // close cURL curl_easy_cleanup(curl); curl_global_cleanup(); // close csv file csvFile.close(); return 0; }
Path findProjectRoot(const Path &path) { assert(path.isAbsolute()); const Path config = findAncestor(path, ".rtags-config", Shallow); if (config.isDir()) { const List<String> conf = Path(config + ".rtags-config").readAll().split('\n'); for (List<String>::const_iterator it = conf.begin(); it != conf.end(); ++it) { const char *ch = it->constData(); while (*ch && isspace(*ch)) ++ch; if (*ch && !strncmp("project: ", ch, 9)) { ch += 9; while (*ch && isspace(*ch)) ++ch; const Path p = ch; if (p.isDir()) { return p.ensureTrailingSlash(); } else { error("Invalid project root %s", p.constData()); } } } } static const Path home = Path::home(); const Entry before[] = { { "GTAGS", 0 }, { "CMakeLists.txt", 0 }, { "configure", 0 }, { ".git", 0 }, { ".svn", 0 }, { "*.pro", Wildcard }, { "scons.1", 0 }, { "*.scons", Wildcard }, { "SConstruct", 0 }, { "autogen.*", Wildcard }, { "GNUMakefile*", Wildcard }, { "INSTALL*", Wildcard }, { "README*", Wildcard }, { 0, 0 } }; { const Path ret = checkEntry(before, path, home); if (!ret.isEmpty()) return ret; } { const Path configStatus = findAncestor(path, "config.status", 0); if (!configStatus.isEmpty()) { FILE *f = fopen((configStatus + "config.status").constData(), "r"); Path ret; if (f) { char line[1024]; enum { MaxLines = 10 }; for (int i=0; i<MaxLines; ++i) { int r = Rct::readLine(f, line, sizeof(line)); if (r == -1) break; char *configure = strstr(line, "/configure "); if (configure) { char *end = configure + 10; while (--configure >= line) { Path conf(configure, end - configure); if (!conf.isAbsolute()) conf.resolve(); if (conf.isFile()) { ret = conf.parentDir(); if (ret == home) ret.clear(); break; } } } if (!ret.isEmpty()) break; } fclose(f); if (!ret.isEmpty()) return ret; } } } { const Path cmakeCache = findAncestor(path, "CMakeCache.txt", 0); if (!cmakeCache.isEmpty()) { FILE *f = fopen((cmakeCache + "Makefile").constData(), "r"); if (f) { Path ret; char line[1024]; enum { MaxLines = 256 }; for (int i=0; i<MaxLines; ++i) { int r = Rct::readLine(f, line, sizeof(line)); if (r == -1) { break; } if (!strncmp(line, "CMAKE_SOURCE_DIR", 16)) { char *dir = line + 16; while (*dir && (*dir == ' ' || *dir == '=')) ++dir; if (dir != home) { ret = dir; ret += '/'; if (!Path(ret + "CMakeLists.txt").isFile()) ret.clear(); } break; } } fclose(f); if (!ret.isEmpty()) return ret; } } } const Entry after[] = { { "Makefile*", Wildcard }, { 0, 0 } }; { const Path ret = checkEntry(after, path, home); if (!ret.isEmpty()) return ret; } return Path(); }
/* * Remove "obj" from "pRef". We extract the table offset bits from "iref" * and zap the corresponding entry, leaving a hole if it's not at the top. * * If the entry is not between the current top index and the bottom index * specified by the cookie, we don't remove anything. This is the behavior * required by JNI's DeleteLocalRef function. * * Note this is NOT called when a local frame is popped. This is only used * for explicit single removals. * * Returns "false" if nothing was removed. */ bool IndirectRefTable::remove(u4 cookie, IndirectRef iref) { IRTSegmentState prevState; prevState.all = cookie; int topIndex = segmentState.parts.topIndex; int bottomIndex = prevState.parts.topIndex; assert(table_ != NULL); assert(alloc_entries_ <= max_entries_); assert(segmentState.parts.numHoles >= prevState.parts.numHoles); int idx = extractIndex(iref); bool workAroundAppJniBugs = false; if (indirectRefKind(iref) == kIndirectKindInvalid && gDvmJni.workAroundAppJniBugs) { idx = linearScan(iref, bottomIndex, topIndex, table_); workAroundAppJniBugs = true; if (idx == -1) { LOGW("trying to work around app JNI bugs, but didn't find %p in table!", iref); return false; } } if (idx < bottomIndex) { /* wrong segment */ LOGV("Attempt to remove index outside index area (%d vs %d-%d)", idx, bottomIndex, topIndex); return false; } if (idx >= topIndex) { /* bad -- stale reference? */ LOGD("Attempt to remove invalid index %d (bottom=%d top=%d)", idx, bottomIndex, topIndex); return false; } if (idx == topIndex-1) { // Top-most entry. Scan up and consume holes. if (workAroundAppJniBugs == false && !checkEntry("remove", iref, idx)) { return false; } table_[idx] = NULL; int numHoles = segmentState.parts.numHoles - prevState.parts.numHoles; if (numHoles != 0) { while (--topIndex > bottomIndex && numHoles != 0) { LOGV("+++ checking for hole at %d (cookie=0x%08x) val=%p", topIndex-1, cookie, table_[topIndex-1]); if (table_[topIndex-1] != NULL) { break; } LOGV("+++ ate hole at %d", topIndex-1); numHoles--; } segmentState.parts.numHoles = numHoles + prevState.parts.numHoles; segmentState.parts.topIndex = topIndex; } else { segmentState.parts.topIndex = topIndex-1; LOGV("+++ ate last entry %d", topIndex-1); } } else { /* * Not the top-most entry. This creates a hole. We NULL out the * entry to prevent somebody from deleting it twice and screwing up * the hole count. */ if (table_[idx] == NULL) { LOGV("--- WEIRD: removing null entry %d", idx); return false; } if (workAroundAppJniBugs == false && !checkEntry("remove", iref, idx)) { return false; } table_[idx] = NULL; segmentState.parts.numHoles++; LOGV("+++ left hole at %d, holes=%d", idx, segmentState.parts.numHoles); } return true; }
void AppSettings::cmdOk_Click(){ if (!checkEntry(txtTarBin->text(), "tar")) return; if (!checkEntry(txtMountBin->text(), "mount")) return; if (!checkEntry(txtUmountBin->text(), "umount")) return; if (!checkEntry(txtSudoBin->text(), "sudo")) return; if (!checkEntry(txtGuiSudoBin->text(), "gui_sudo")) return; if (!checkEntry(txtUmountBin->text(), "nice")) return; if (!checkEntry(txtUmountBin->text(), "renice")) return; if (!checkEntry(txtUmountBin->text(), "sh")) return; if (!checkEntry(txtConsoleBin->text(), "console")) return; #ifdef WITH_ICOUTILS if (!checkEntry(txtWrestoolBin->text(), "wrestool")) return; if (!checkEntry(txtIcotoolBin->text(), "icotool")) return; #endif if (comboProxyType->currentText()!=tr("No Proxy")){ if (txtProxyHost->text().isEmpty()){ QMessageBox::warning(this, tr("Error"), tr("Sorry, specify proxy host.")); return; } if (txtProxyPort->text().isEmpty()){ QMessageBox::warning(this, tr("Error"), tr("Sorry, specify proxy port.")); return; } } QSettings settings(APP_SHORT_NAME, "default"); settings.beginGroup("logging"); if (cbClearLogs->checkState()==Qt::Checked) { settings.setValue("autoClear", 1); } else { settings.setValue("autoClear", 0); } settings.endGroup(); settings.beginGroup("app"); if (comboAppIcons->currentText() == tr("Ambient Light")){ settings.setValue("icon", "q4wine-ambiance"); } else if (comboAppIcons->currentText() == tr("Ambient Dark")){ settings.setValue("icon", "q4wine-ambiance-dark"); } else { settings.setValue("icon", "q4wine"); } if (cbShowTray->checkState()==Qt::Checked) { settings.setValue("showTrareyIcon", 1); } else { settings.setValue("showTrareyIcon", 0); } if (cbMinimizeToTray->checkState()==Qt::Checked) { settings.setValue("minimizeToTray", 1); } else { settings.setValue("minimizeToTray", 0); } if (cbMinimizeToTrayApp->checkState()==Qt::Checked) { settings.setValue("minimizeToTrayAtAppStart", 1); } else { settings.setValue("minimizeToTrayAtAppStart", 0); } if (cbShowNotifications->checkState()==Qt::Checked) { settings.setValue("showNotifications", 1); } else { settings.setValue("showNotifications", 0); } if (comboLangs->currentText()==tr("System Default")){ settings.setValue("lang", ""); } else { settings.setValue("lang", lng_hash[comboLangs->currentText()]); } settings.endGroup(); settings.beginGroup("system"); settings.setValue("tar", txtTarBin->text()); settings.setValue("mount", txtMountBin->text()); settings.setValue("umount", txtUmountBin->text()); settings.setValue("sudo", txtSudoBin->text()); settings.setValue("gui_sudo", txtGuiSudoBin->text()); settings.setValue("nice", txtNiceBin->text()); settings.setValue("renice", txtReniceBin->text()); settings.setValue("sh", txtShBin->text()); settings.endGroup(); settings.beginGroup("console"); settings.setValue("bin", txtConsoleBin->text()); settings.setValue("args", txtConsoleArgs->text()); settings.endGroup(); #ifdef WITH_ICOUTILS settings.beginGroup("icotool"); settings.setValue("wrestool", txtWrestoolBin->text()); settings.setValue("icotool", txtIcotoolBin->text()); settings.endGroup(); #endif settings.beginGroup("quickmount"); settings.setValue("type", this->comboMountProfiles->currentIndex()); settings.setValue("mount_drive_string", txtMountString->text()); settings.setValue("mount_image_string", txtMountImageString->text()); settings.setValue("umount_string", txtUmountString->text()); settings.endGroup(); settings.beginGroup("network"); settings.setValue("host", txtProxyHost->text()); settings.setValue("port", txtProxyPort->text()); settings.setValue("user", txtProxyUser->text()); settings.setValue("pass", txtProxyPass->text()); if (comboProxyType->currentText()==tr("No Proxy")){ settings.setValue("type", 0); } else { if (comboProxyType->currentText()=="HTTP"){ settings.setValue("type", 1); } else { settings.setValue("type", 2); } } settings.endGroup(); settings.beginGroup("advanced"); settings.setValue("prefixDefaultPath", txtDefPrefixPath->text()); if (cbOpenRunDialog->isChecked()){ settings.setValue("openRunDialog", 1); } else { settings.setValue("openRunDialog", 0); } if (cbUseSingleClick->isChecked()){ settings.setValue("useSingleClick", 1); } else { settings.setValue("useSingleClick", 0); } #if QT_VERSION >= 0x040500 if (cbUseNativeDialog->isChecked()){ settings.setValue("useNativeFileDialog", 1); } else { settings.setValue("useNativeFileDialog", 0); } #endif QString desktopSize=cboxDesktopSize->currentText(); if (desktopSize==tr("No virtual desktop")) desktopSize=""; settings.setValue("defaultDesktopSize", desktopSize); settings.endGroup(); settings.beginGroup("DesktopImport"); if (cbRemoveDesktopFiles->isChecked()){ settings.setValue("remove", 1); } else { settings.setValue("remove", 0); } if (cbImportDesktopFilesAtStartup->isChecked()){ settings.setValue("importAtStartup", 1); } else { settings.setValue("importAtStartup", 0); } settings.endGroup(); settings.beginGroup("AppDB"); if (cbUseSystemBrowser->isChecked()){ settings.setValue("useSystemBrowser", 1); } else { settings.setValue("useSystemBrowser", 0); } settings.endGroup(); #ifndef _OS_DARWIN_ settings.beginGroup("Plugins"); if (cbEnableDesktopMenu->isChecked()){ settings.setValue("enableMenuDesktop", 1); } else { settings.setValue("enableMenuDesktop", 0); } settings.endGroup(); #endif accept(); return; }