示例#1
0
    def execute(self):
        resultData = ResultData()
        errorDetails = self.parsedParmData[self.COMMAND_ERROR_MSG_KEY]
        errorType = self.parsedParmData[self.COMMAND_ERROR_TYPE_KEY]
        errorTypeLabelStr = ''
        errorMsgTail = '.'

        if errorType == self.COMMAND_ERROR_TYPE_FULL_REQUEST:
            errorTypeLabelStr = 'full request'
            errorMsgTail = ' violates format <crypto> <unit> <date|time> <exchange> <options>.'
        elif errorType == self.COMMAND_ERROR_TYPE_FULL_REQUEST_OPTION:
            errorTypeLabelStr = 'full request'
        elif errorType == self.COMMAND_ERROR_TYPE_PARTIAL_REQUEST:
            errorTypeLabelStr = 'invalid partial request'
        elif errorType == self.COMMAND_ERROR_TYPE_INVALID_COMMAND:
            errorTypeLabelStr = 'invalid request'
        elif errorType == self.COMMAND_ERROR_TYPE_PARTIAL_REQUEST_WITH_NO_PREVIOUS_FULL_REQUEST:
            errorTypeLabelStr = 'no full request executed before partial request'
            errorMsgTail = '. Partial request ignored.'

        if errorDetails != '':
            errorDetails = ': ' + errorDetails

        resultData.setError("ERROR - {} {}{}{}".format(errorTypeLabelStr,
                                                       self.requestInputString,
                                                       errorDetails,
                                                       errorMsgTail))

        return resultData
示例#2
0
    def _validateCryptoUnitParms(self):
        """
		Return True if the defined cryoto and unit symbols exists and are
		valid Otherwise, returns a ResultData containing an error msg.
		
		In case only one crypto or unit symbol is entered, the Requester
		accepts the symbol as crypto. For this reason, the crypto can
		not be None !
		"""
        resultData = True

        crypto = self.parsedParmData[self.CRYPTO]

        if any(char.isdigit() for char in crypto):
            # In case only one crypto or unit symbol is entered, the Requester
            # accepts the symbol as crypto. For this reason, the crypto can
            # not be None !
            resultData = ResultData()
            resultData.setError("ERROR - invalid crypto.")
            return resultData

        unit = self.parsedParmData[self.UNIT]

        if unit == None or any(char.isdigit() for char in unit):
            resultData = ResultData()
            resultData.setError("ERROR - unit missing or invalid.")
            return resultData

        return resultData
示例#3
0
    def getCurrentPrice(self, crypto, unit, exchange):
        url = "https://min-api.cryptocompare.com/data/price?fsym={}&tsyms={}&e={}".format(crypto, unit, exchange)
        resultData = ResultData()

        resultData.setValue(ResultData.RESULT_KEY_CRYPTO, crypto)
        resultData.setValue(ResultData.RESULT_KEY_UNIT, unit)
        resultData.setValue(ResultData.RESULT_KEY_EXCHANGE, exchange)
        resultData.setValue(ResultData.RESULT_KEY_PRICE_TYPE, resultData.PRICE_TYPE_RT)

        try:
            if self.ctx == None:
                #here, run in QPython under Python 3.2
                webURL = urllib.request.urlopen(url)
            else:
                webURL = urllib.request.urlopen(url, context=self.ctx)
        except HTTPError as e:
            resultData.setError('ERROR - could not complete request ' + url + '. Reason: ' + str(e.reason) + '.')
        except URLError as e:
            resultData.setError('ERROR - No internet. Please connect and retry !')
        except: 
            the_type, the_value, the_traceback = sys.exc_info()
            resultData.setError('ERROR - could not complete request ' + url + '. Reason: ' + str(the_type) + '.')
        else:
            page = webURL.read()
            soup = BeautifulSoup(page, 'html.parser')
            dic = json.loads(soup.prettify())
            
            if unit in dic:
                resultData.setValue(ResultData.RESULT_KEY_PRICE_TIME_STAMP, DateTimeUtil.utcNowTimeStamp())
                resultData.setValue(ResultData.RESULT_KEY_PRICE, dic[unit]) #current price is indexed by unit symbol in returned dic
            else:
                resultData = self._handleProviderError(dic, resultData, url, crypto, unit, exchange, isRealTime=True)

        return resultData
示例#4
0
class TestResultData(unittest.TestCase):
    def setUp(self):
        self.resultData = ResultData()


    def testInit(self):
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_CRYPTO), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_UNIT), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_EXCHANGE), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_PRICE_TIME_STAMP), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_PRICE_DATE_TIME_STRING), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_PRICE), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_PRICE_TYPE), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_ERROR_MSG), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_WARNINGS_DIC), {})
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_INITIAL_COMMAND_PARMS), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_VALUE_CRYPTO), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_VALUE_UNIT), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_VALUE_FIAT), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_VALUE_SAVE), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_FIAT_RATE), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_FIAT_COMPUTED_AMOUNT), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_FIAT_SYMBOL), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_FIAT_EXCHANGE), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_FIAT_SAVE), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_PRICE_AMOUNT), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_PRICE_SAVE), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_RESULT_COMPUTED_AMOUNT_UNIT), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_RESULT_COMPUTED_PERCENT_UNIT), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_RESULT_COMPUTED_AMOUNT_FIAT), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_RESULT_COMPUTED_PERCENT_FIAT), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_RESULT_SAVE), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_LIMIT_AMOUNT), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_LIMIT_COMPUTED_UNIT_AMOUNT), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_LIMIT_SYMBOL), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_LIMIT_EXCHANGE), None)
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_OPTION_LIMIT_SAVE), None)
        

    def testNoError(self):
        self.assertTrue(self.resultData.noError())
        
        errorMsg = "ERROR - test error"
        
        self.resultData.setError(errorMsg)
        self.assertFalse(self.resultData.noError())


    def testSetValue(self):
        self.resultData.setValue(self.resultData.RESULT_KEY_CRYPTO, 'USD')
        self.assertEqual(self.resultData.getValue(self.resultData.RESULT_KEY_CRYPTO), 'USD')


    def testSetGetWarning(self):
        commValWarningMsg = "test warning command value"
        futureDateWarningMsg = "test warning future date"

        self.resultData.setWarning(ResultData.WARNING_TYPE_OPTION_VALUE, commValWarningMsg)
        self.resultData.setWarning(ResultData.WARNING_TYPE_FUTURE_DATE, futureDateWarningMsg)

        self.assertEqual(commValWarningMsg, self.resultData.getWarningMessage(ResultData.WARNING_TYPE_OPTION_VALUE))
        self.assertEqual(futureDateWarningMsg, self.resultData.getWarningMessage(ResultData.WARNING_TYPE_FUTURE_DATE))


    def testGetAllWarningMessages(self):
        commValWarningMsg = "test warning command value"
        futureDateWarningMsg = "test warning future date"

        self.resultData.setWarning(ResultData.WARNING_TYPE_OPTION_VALUE, commValWarningMsg)
        self.resultData.setWarning(ResultData.WARNING_TYPE_FUTURE_DATE, futureDateWarningMsg)

        self.assertEqual([commValWarningMsg, futureDateWarningMsg], self.resultData.getAllWarningMessages())


    def testContainsWarning(self):
        commValWarningMsg = "test warning command value"
        futureDateWarningMsg = "test warning future date"

        self.assertFalse(self.resultData.containsWarnings())

        self.resultData.setWarning(ResultData.WARNING_TYPE_OPTION_VALUE, commValWarningMsg)
        self.assertTrue(self.resultData.containsWarning(ResultData.WARNING_TYPE_OPTION_VALUE))
        self.assertFalse(self.resultData.containsWarning(ResultData.WARNING_TYPE_FUTURE_DATE))

        self.resultData.setWarning(ResultData.WARNING_TYPE_FUTURE_DATE, futureDateWarningMsg)
        self.assertTrue(self.resultData.containsWarning(ResultData.WARNING_TYPE_FUTURE_DATE))


    def testOverwriteWarning(self):
        commValWarningMsgOne = "test warning command value one"
        futureDateWarningMsgOne = "test warning future date one"

        self.resultData.setWarning(ResultData.WARNING_TYPE_OPTION_VALUE, commValWarningMsgOne)
        self.resultData.setWarning(ResultData.WARNING_TYPE_FUTURE_DATE, futureDateWarningMsgOne)

        commValWarningMsgTwo = "test warning command value two"
        futureDateWarningMsgTwo = "test warning future date two"

        self.resultData.setWarning(ResultData.WARNING_TYPE_OPTION_VALUE, commValWarningMsgTwo)
        self.resultData.setWarning(ResultData.WARNING_TYPE_FUTURE_DATE, futureDateWarningMsgTwo)

        self.assertEqual(commValWarningMsgTwo, self.resultData.getWarningMessage(ResultData.WARNING_TYPE_OPTION_VALUE))
        self.assertEqual(futureDateWarningMsgTwo, self.resultData.getWarningMessage(ResultData.WARNING_TYPE_FUTURE_DATE))
示例#5
0
	def getCryptoPrice(self,
					   crypto,
					   unit,
					   exchange,
					   day,
					   month,
					   year,
					   hour,
					   minute,
					   optionValueSymbol=None,
					   optionValueAmount=None,
					   optionValueSaveFlag=None,
					   optionFiatSymbol=None,
					   optionFiatExchange=None,
					   optionPriceAmount=None,
					   optionPriceSaveFlag=None,
					   optionResultStrAmount=None,
					   optionResultSaveFlag=None,
					   optionLimitSymbol=None,
					   optionLimitAmount=None,
					   optionLimitExchange=None,
					   optionLimitSaveFlag=None,
					   requestInputString=''):
		"""
		Ask the PriceRequester either a RT price or a historical price. Then,
		in case a fiat (-f) or/and a value option (-v) was specified, computes
		them and add the results to the returned ResultData.
		
		:param crypto:
		:param unit:
		:param exchange:
		:param day:
		:param month:
		:param year:
		:param hour:
		:param minute:
		:param optionValueSymbol: upper case currency value symbol. If == crypto, this means that optionValueAmount provided
								  is in crypto and must be converted into unit (counter party) at the rate returned by
								  the PriceRequester.

								  If the currency value symbol == unit, this means that optionValueAmount provided
								  is in the counter party (unit or an other crypto) and must be converted into crypto at
								  the rate returned by the PriceRequester.

								  Ex 1:  -v0.001btc
										crypto == BTC
										unit == USD
										optionValueSymbol == BTC
										optionValueAmount == 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
										unit == USD
										optionValueSymbol == USD
										optionValueAmount == 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 optionValueAmount:   float specified value option amount
		:param optionValueSaveFlag: used to refine warning if value option not applicable
		:param optionFiatSymbol:    stores the fiat symbol, i.e. the fiat into which the returned
									unit amount is converted
		:param optionFiatExchange:
		:param optionPriceAmount:
		:param optionPriceSaveFlag: not sure if useful. May be used to refine warning if price option
									not applicable
		:param optionResultStrAmount: ex: '' means -1 or -2 or -1-3 or -2:-4
		:param optionResultSaveFlag:  not sure if useful. May be used to refine warning if result option
									  not applicable
		:param optionLimitSymbol:
		:param optionLimitAmount:
		:param optionLimitExchange:
		:param optionLimitSaveFlag: not sure if useful. May be used to refine warning if limit option
									not applicable
		:param requestInputString): used for to complete the error msg with the request
									causing problem!
		:seqdiag_return ResultData
		:return: a ResultData filled with result values
		"""
		
		# validating exchange, fiat exchange and limit exchange
		
		if exchange == None:
			resultData = ResultData()
			resultData.setError("ERROR - exchange could not be parsed due to an error in your request ({}).".format(requestInputString))
			return resultData
		else:
			try:
				validCryptoUnitExchangeSymbol = self.crypCompExchanges.getExchange(exchange)
			except(KeyError):
				resultData = ResultData()
				resultData.setError(MARKET_NOT_SUPPORTED_ERROR.format(exchange))
				return resultData

		validFiatExchangeSymbol = None

		if optionFiatExchange:
			try:
				validFiatExchangeSymbol = self.crypCompExchanges.getExchange(optionFiatExchange)
			except(KeyError):
				resultData = ResultData()
				resultData.setError(MARKET_NOT_SUPPORTED_ERROR.format(optionFiatExchange))
				return resultData

		validLimitExchangeSymbol = None

		if optionLimitExchange:
			try:
				validLimitExchangeSymbol = self.crypCompExchanges.getExchange(optionLimitExchange)
			except(KeyError):
				resultData = ResultData()
				resultData.setError(MARKET_NOT_SUPPORTED_ERROR.format(optionLimitExchange))
				return resultData

		localTz = self.configManager.localTimeZone
		dateTimeFormat = self.configManager.dateTimeFormat

		resultData = self._getPrice(crypto,
									unit,
									validCryptoUnitExchangeSymbol,
									year,
									month,
									day,
									hour,
									minute,
									dateTimeFormat,
									localTz,
									optionPriceAmount,
									optionPriceSaveFlag)


		if not resultData.noError():
			# since crypto/unit is not supported by the exchange, we try to request the unit/crypto inverted rate
			errorMsg = resultData.getErrorMessage()
			resultData = self._getPrice(unit,
										crypto,
										validCryptoUnitExchangeSymbol,
										year,
										month,
										day,
										hour,
										minute,
										dateTimeFormat,
										localTz,
										optionPriceAmount)

			resultData.setValue(resultData.RESULT_KEY_CRYPTO, crypto)
			resultData.setValue(resultData.RESULT_KEY_UNIT, unit)
			price = resultData.getValue(resultData.RESULT_KEY_PRICE)

			if price:
				resultData.setValue(resultData.RESULT_KEY_PRICE, 1 / price)
				resultData.setError(None)
			else:
				resultData.setError(errorMsg)
				
		if optionPriceAmount is not None and resultData.noError():
			resultData.setValue(resultData.RESULT_KEY_PRICE, optionPriceAmount)
			resultData.setValue(resultData.RESULT_KEY_PRICE_TYPE, resultData.PRICE_TYPE_EFFECTIVE)
		
		if optionFiatSymbol is not None and resultData.noError():
			resultData = self._computeOptionFiatAmount(resultData,
													   optionFiatSymbol,
													   validFiatExchangeSymbol,
													   crypto,
													   unit,
													   validCryptoUnitExchangeSymbol,
													   year,
													   month,
													   day,
													   hour,
													   minute,
													   dateTimeFormat,
													   localTz)

		if optionValueSymbol is not None and resultData.noError():
			resultData = self._computeOptionValueAmount(resultData,
														crypto,
														unit,
														optionFiatSymbol,
														optionValueSymbol,
														optionValueAmount,
														optionValueSaveFlag)

		return resultData
示例#6
0
    def _completeAndValidateDateTimeData(self, localNow):
        '''
		Sets missing request date components to their current date value. Also ensures that
		date/time info contained in the parsedParmData dic are valid and in	a right format.
		If everything is ok, returns True.

		:param localNow:
		
		:return: True if date/time values stored in the parsedParmData dic are valid. If an
				 error was detected, a new ResultData with a meaningfull error msg is
				 returned.
		'''

        dtFormatDic = DateTimeUtil.getDateAndTimeFormatDictionary(
            self.configManager.dateTimeFormat)

        dateShortFormat = dtFormatDic[DateTimeUtil.SHORT_DATE_FORMAT_KEY]
        dateLongFormat = dtFormatDic[DateTimeUtil.LONG_DATE_FORMAT_KEY]
        timeFormat = dtFormatDic[DateTimeUtil.TIME_FORMAT_KEY]

        resultData = True

        dayStr = self.parsedParmData[self.DAY]
        monthStr = self.parsedParmData[self.MONTH]
        yearStr = self.parsedParmData[self.YEAR]
        hourStr = self.parsedParmData[self.HOUR]
        minuteStr = self.parsedParmData[self.MINUTE]

        if (yearStr == '0' and monthStr == '0' and dayStr == '0'):
            # RT price asked
            return True
        else:
            # Here, the three date components are not all equal to 0 !
            if (yearStr == None and monthStr == None and dayStr == None
                    and hourStr != None and minuteStr != None):
                # Here, only time was specified in the full request, which is now possible.
                # Current day, month and year are formatted into the parsed parm data
                # and True is returned
                self.parsedParmData[self.DAY] = localNow.format('DD')
                self.parsedParmData[self.MONTH] = localNow.format('MM')
                self.parsedParmData[self.YEAR] = localNow.format('YYYY')
                return True
            elif (yearStr == None and monthStr == None and dayStr != None
                  and hourStr != None and minuteStr != None):
                # Here, only day and time were specified in the full request, which is now possible.
                # Current month and year are formatted into the parsed parm data
                # and True is returned
                self.parsedParmData[self.MONTH] = localNow.format('MM')
                self.parsedParmData[self.YEAR] = localNow.format('YYYY')
                return True
            elif (yearStr == '0' or
                  # yearStr is None when only day/month specified -> valid !
                  monthStr == '0' or monthStr == None or dayStr == '0'
                  or dayStr == None):
                # only when user enters -d0 for RT price,
                # is yearStr equal to '0' since 0 is put
                # by Requester into day, month and year !
                if dayStr is not None and monthStr is None and yearStr is None:
                    # here, only the day was specified in the full request.
                    # Example: chsb btc 19 hitbtc.
                    # Handling day only date in full request makes it coherent
                    # with partial -d request where -d23 for example is ok !
                    self.parsedParmData[self.MONTH] = localNow.format('MM')
                    self.parsedParmData[self.YEAR] = localNow.format('YYYY')
                    self.parsedParmData[self.HOUR] = str(localNow.hour)
                    self.parsedParmData[self.MINUTE] = str(localNow.minute)
                    return True
                else:
                    resultData = ResultData()
                    resultData.setError("ERROR - date not valid.")
                    return resultData
            elif len(monthStr) > 2:
                resultData = ResultData()
                resultData.setError(
                    "ERROR - {} not conform to accepted month format (MM or M)."
                    .format(monthStr))
                return resultData
            elif yearStr != None:
                yearStrLen = len(yearStr)
                if yearStrLen != 2 and yearStrLen != 4:
                    resultData = ResultData()
                    resultData.setError(
                        "ERROR - {} not conform to accepted year format (YYYY, YY or '')."
                        .format(yearStr))

                    # avoiding that invalid year will pollute next price requests
                    self.parsedParmData[self.YEAR] = None
                    return resultData

            # validating full date. Catch invalid day or invalid month,
            # like day == 123 or day == 32 or month == 31
            if yearStr == None:
                yearStr = str(localNow.year)

            if hourStr == None:
                hourStr = str(localNow.hour)

            if minuteStr == None:
                minuteStr = str(localNow.minute)

            dateTimeTupleList = [('day', dayStr, dateShortFormat),
                                 ('month', monthStr, dateShortFormat),
                                 ('year', yearStr, dateLongFormat),
                                 ('hour', hourStr, timeFormat),
                                 ('minute', minuteStr, timeFormat)]

            try:
                for name, value, format in dateTimeTupleList:
                    int(value)
            except ValueError as e:
                resultData = ResultData()
                resultData.setError(
                    "ERROR - invalid value: {} violates format for {} ({}).".
                    format(value, name, format))
                return resultData

            try:
                _ = DateTimeUtil.dateTimeComponentsToArrowLocalDate(
                    int(dayStr), int(monthStr), int(yearStr), int(hourStr),
                    int(minuteStr), 0, self.configManager.localTimeZone)
            except ValueError as e:
                resultData = ResultData()
                resultData.setError("ERROR - " + str(e) + '.')

        return resultData
示例#7
0
    def _handleDateTimeRequestParms(self):
        '''
		Complete missing request date elements with current date values and validate
		request date and time elements format. Then converts or computes date and time
		elements to int.
		
		In case the resulting date is in the future, its year is reduced by one and
		the returned localRequestDateTime is not None !
		
		:return: day, month, year, hour, minute
				 localRequestDateTime None, except if the (effective or completed)
									  request date is in the future
				 resultPriceOrBoolean
		'''
        day = None
        month = None
        year = None
        hour = None
        minute = None
        localRequestDateTime = None

        localTimezone = self.configManager.localTimeZone
        localNow = DateTimeUtil.localNow(localTimezone)

        resultPriceOrBoolean = self._completeAndValidateDateTimeData(localNow)

        # storing the parsed parm data dictionary before it
        # may be modified in case the user requested a RT
        # price. The initial dictionary wiLl be added to the
        # returned resultData so the client can have access
        # to the full command request, even if only a partial
        # request like -d or -c was entered. This is necessary
        # because if the client is a GUI, it stores the list
        # of requests in order to be able to replay them !
        initialParsedParmDataDic = self.parsedParmData.copy()

        if resultPriceOrBoolean == True:
            dayStr = self.parsedParmData[self.DAY]
            day = int(dayStr)

            monthStr = self.parsedParmData[self.MONTH]

            if monthStr != None:
                month = int(monthStr)
            else:
                month = localNow.month

            yearStr = self.parsedParmData[self.YEAR]

            if yearStr != None:
                if len(yearStr) == 2:
                    year = 2000 + int(yearStr)
                elif len(yearStr) == 4:
                    year = int(yearStr)
                elif yearStr == '0':  # user entered -d0 !
                    year = 0
            else:
                year = localNow.year

            hourStr = self.parsedParmData[self.HOUR]

            if hourStr != None:
                hour = int(hourStr)
            else:
                hour = 0

            minuteStr = self.parsedParmData[self.MINUTE]

            if minuteStr != None:
                minute = int(minuteStr)
            else:
                minute = 0

            localRequestDateTime = None

            if day + month + year == 0:
                # asking for RT price here. Current date is stored in parsed parm data for possible
                # use in next request
                self._storeDateTimeDataForNextPartialRequest(localNow)
            else:
                try:
                    localRequestDateTime = DateTimeUtil.dateTimeComponentsToArrowLocalDate(
                        day, month, year, hour, minute, 0, localTimezone)
                except ValueError as e:
                    # is the case when the user specify only the day if he enters 31 and the current month
                    # has no 31st or if he enters 30 or 29 and we are on February
                    resultPriceOrBoolean = ResultData()
                    resultPriceOrBoolean.setError(
                        "ERROR - {}: day {}, month {}.".format(
                            str(e), day, month))

                if resultPriceOrBoolean == True:
                    if DateTimeUtil.isAfter(localRequestDateTime, localNow):
                        # request date is in the future ---> invalid. This happens for example in case
                        # btc usd 31/12 bittrex entered sometime before 31/12. Then the request year is
                        # forced to last year and a warning will be displayed.
                        year = localNow.year - 1
                    else:
                        localRequestDateTime = None

        return day, month, year, hour, minute, localRequestDateTime, resultPriceOrBoolean, initialParsedParmDataDic