def _getPrice(self, currency, targetCurrency, exchange, year, month, day, hour, minute, dateTimeFormat, localTz, optionPriceAmount=None, optionPriceSaveFlag=None): ''' Returns the price of 1 unit of currency in targetCurrency. Ex: currency == btc, targetCurrency == usd --> returned price: 1 btc == 10000 usd. :param currency: :param targetCurrency: :param exchange: :param year: :param month: :param day: :param hour: :param minute: :param dateTimeFormat: :param localTz: :param optionPriceAmount: :param optionPriceSaveFlag: used to improve option price warning in case set in conjunction with RT request. :seqdiag_return ResultData :return: ''' if (day + month + year) == 0: # when the user specifies 0 for the date, this means current price is asked and # date components are set to zero ! resultData = self.priceRequester.getCurrentPrice(currency, targetCurrency, exchange) if resultData.noError(): # adding date time info if no error returned timeStamp = resultData.getValue(ResultData.RESULT_KEY_PRICE_TIME_STAMP) requestedPriceArrowLocalDateTime = DateTimeUtil.timeStampToArrowLocalDate(timeStamp, localTz) requestedDateTimeStr = requestedPriceArrowLocalDateTime.format(dateTimeFormat) resultData.setValue(ResultData.RESULT_KEY_PRICE_DATE_TIME_STRING, requestedDateTimeStr) if optionPriceAmount: # option price not compatible with RT request ! if optionPriceSaveFlag: optionStrForWarning = '-ps' else: optionStrForWarning = '-p' resultData.setWarning(ResultData.WARNING_TYPE_OPTION_PRICE, "WARNING - option {}{} is not compatible with real time request. {} option ignored.".format( optionStrForWarning, optionPriceAmount, optionStrForWarning)) else: # getting historical price, either histo day or histo minute timeStampLocal = DateTimeUtil.dateTimeComponentsToTimeStamp(day, month, year, hour, minute, 0, localTz) timeStampUtcNoHHMM = DateTimeUtil.dateTimeComponentsToTimeStamp(day, month, year, 0, 0, 0, 'UTC') resultData = self.priceRequester.getHistoricalPriceAtUTCTimeStamp(currency, targetCurrency, timeStampLocal, localTz, timeStampUtcNoHHMM, exchange) if resultData.noError(): # adding date time info if no error returned if resultData.getValue(ResultData.RESULT_KEY_PRICE_TYPE) == ResultData.PRICE_TYPE_HISTO_MINUTE: # histominute price returned requestedPriceArrowLocalDateTime = DateTimeUtil.timeStampToArrowLocalDate(timeStampLocal, localTz) requestedDateTimeStr = requestedPriceArrowLocalDateTime.format(dateTimeFormat) elif optionPriceAmount: # here, the -p price option is active and the transaction date with minute # precision must be set in the returned ResultData requestedPriceArrowLocalDateTime = DateTimeUtil.timeStampToArrowLocalDate(timeStampLocal, localTz) requestedDateTimeStr = requestedPriceArrowLocalDateTime.format(dateTimeFormat) else: # histoday price returned requestedPriceArrowUtcDateTime = DateTimeUtil.timeStampToArrowLocalDate(timeStampUtcNoHHMM, 'UTC') requestedDateTimeStr = requestedPriceArrowUtcDateTime.format(dateTimeFormat) resultData.setValue(ResultData.RESULT_KEY_PRICE_DATE_TIME_STRING, requestedDateTimeStr) price = resultData.getValue(ResultData.RESULT_KEY_PRICE) if price == 0: dateDMY, dateHM = DateTimeUtil.formatPrintDateTimeFromIntComponents(day, month, year, hour, minute, localTz, dateTimeFormat) resultData.setError('PROVIDER ERROR - Requesting {}/{} price for date {} {} on exchange {} returned invalid value 0'.format(currency, targetCurrency, dateDMY, dateHM, exchange)) return resultData
def testDateTimeComponentsSecondNonZeroToTimeStamp(self): absoluteTimeStamp = DateTimeUtil.dateTimeComponentsToTimeStamp(30, 9, 2017, 2, 0, 1, 'Europe/Zurich') self.assertEqual(1506729601, absoluteTimeStamp)
def getCryptoPrice(self, crypto, fiat, exchange, day, month, year, hour, minute, priceValueSymbol = None, priceValueAmount = None, priceValueSaveFlag = None, requestInputString = ''): ''' Ask the PriceRequester either a RT price or a historical price. Then, in case a price value parm (-v) was specified, does the conversion and add its result to the returned ResultData :param crypto: upper case crypto symbol :param fiat: upper case fiat symbol :param exchange: exchange name :param day: int day number :param month: int month number :param year: int year number :param hour: int hour number :param minute: int minute number :param priceValueSymbol: upper case price value symbol. If == crypto, this means that priceValueAmount provided is in crypto and must be converted into fiat at the rate returned by the PriceRequester. If the price value symbol == fiat, this means that priceValueAmount provided is in fiat and must be converted into crypto at the rate returned by the PriceRequester. Ex 1: -v0.001btc crypto == BTC fiat == USD priceValueSymbol == BTC priceValueAmount == 0.001 if returned rate (stored in ResultData.RESULT_KEY_PRICE entry) is 20000, converted value will be 20000 USD * 0.001 BTC => 200 USD Ex 2: -v500usd crypto == BTC fiat == USD priceValueSymbol == USD priceValueAmount == 500 if returned rate (stored in ResultData.RESULT_KEY_PRICE entry) is 20000, converted value will be 1 / 20000 USD * 500 USD => 0.025 BTC :param priceValueAmount: float price value amount :param priceValueSaveFlag: used to refine warning if value command not applicable :param requestInputString): used for better error msg ! :seqdiag_return ResultData :return: a ResultData filled with result values ''' if exchange == None: resultData = ResultData() resultData.setValue(ResultData.RESULT_KEY_ERROR_MSG, "ERROR - exchange could not be parsed due to an error in your request ({})".format(requestInputString)) return resultData else: #this responsability is specific to the PriceRequester and should be moved to it ! try: validExchangeSymbol = self.crypCompExchanges.getExchange(exchange) except(KeyError): resultData = ResultData() resultData.setValue(ResultData.RESULT_KEY_ERROR_MSG, "ERROR - {} market does not exist for this coin pair ({}-{})".format(exchange, crypto, fiat)) return resultData localTz = self.configManager.localTimeZone dateTimeFormat = self.configManager.dateTimeFormat if (day + month + year) == 0: # when the user specifies 0 for either the date, # this means current price is asked and date components # are set to zero ! resultData = self.priceRequester.getCurrentPrice(crypto, fiat, validExchangeSymbol) if resultData.isEmpty(ResultData.RESULT_KEY_ERROR_MSG): #adding date time info if no error returned timeStamp = resultData.getValue(ResultData.RESULT_KEY_PRICE_TIME_STAMP) requestedPriceArrowLocalDateTime = DateTimeUtil.timeStampToArrowLocalDate(timeStamp, localTz) requestedDateTimeStr = requestedPriceArrowLocalDateTime.format(dateTimeFormat) resultData.setValue(ResultData.RESULT_KEY_PRICE_DATE_TIME_STRING, requestedDateTimeStr) else: #getting historical price, either histo day or histo minute timeStampLocal = DateTimeUtil.dateTimeComponentsToTimeStamp(day, month, year, hour, minute, 0, localTz) timeStampUtcNoHHMM = DateTimeUtil.dateTimeComponentsToTimeStamp(day, month, year, 0, 0, 0, 'UTC') resultData = self.priceRequester.getHistoricalPriceAtUTCTimeStamp(crypto, fiat, timeStampLocal, timeStampUtcNoHHMM, validExchangeSymbol) if resultData.isEmpty(ResultData.RESULT_KEY_ERROR_MSG): #adding date time info if no error returned if resultData.getValue(ResultData.RESULT_KEY_PRICE_TYPE) == ResultData.PRICE_TYPE_HISTO_DAY: #histoday price returned requestedPriceArrowUtcDateTime = DateTimeUtil.timeStampToArrowLocalDate(timeStampUtcNoHHMM, 'UTC') requestedDateTimeStr = requestedPriceArrowUtcDateTime.format(self.configManager.dateTimeFormat) else: requestedPriceArrowLocalDateTime = DateTimeUtil.timeStampToArrowLocalDate(timeStampLocal, localTz) requestedDateTimeStr = requestedPriceArrowLocalDateTime.format(dateTimeFormat) resultData.setValue(ResultData.RESULT_KEY_PRICE_DATE_TIME_STRING, requestedDateTimeStr) if priceValueSymbol != None and not resultData.isError(): resultData = self._computePriceValue(resultData, crypto, fiat, priceValueSymbol, priceValueAmount, priceValueSaveFlag) return resultData