def __init__(self, value=36, min_val=None, max_val=None): """ Constructor. To filter by a specific value, set value to a number. To filter by a range, set value to None, and set min_val and max_val to integers. :param value: int - exact term value (default: 36) :param min_val: int - minimum term value (inclusive) (default: None) :param max_val: int - maximum term value (inclusive) (default: None) """ if value is not None and (min_val is not None or max_val is not None): fstr = "value and min_val, max_val are mutually exclusive" details = "value: {}".format(value) if min_val is not None: details += ", min_val: {}".format(min_val) if max_val is not None: details += ", max_val: {}".format(max_val) raise LCError(fstr, details=details) if min_val is not None and max_val is not None: if max_val > min_val: fstr = "max_val cannot be greater than min_val" raise LCError(fstr) elif value is None and (min_val is None or max_val is None): fstr = "invalid specification on the values" hint = "either value or min_val + max_val combo should be specified" raise LCError(fstr, hint=hint) self._value = value self._min_value = min_val self._max_value = max_val
def add(investor_id, amount, frequency=TransferFrequency.NOW, start_date=None, end_date=None): """ Add fund to the account :param investor_id: int - the investor account id :param amount: float - amount to withdraw :param frequency: member of lendingclub2.config.TransferFrequency (default: TransferFrequency.NOW) :param start_date: instance of datetime.datetime - required if frequency is not TransferFrequency.NOW (default: None) :param end_date: instance of datetime.datetime - optional (default: None) :returns: instance of lendingclub2.response.Response """ url = DNS + ENDPOINTS['transfer'].format(version=API_VERSION, investor_id=investor_id) if not isinstance(frequency, TransferFrequency): fstr = "frequency parameter is not instance of TransferFrequency" raise LCError(fstr) if frequency != TransferFrequency.NOW: if start_date is None: fstr = "please specify start_date to transfer fund" hint = "start_date needs to be specified for future or recurring " \ "transfer" raise LCError(fstr, hint=hint) elif not isinstance(start_date, datetime.datetime): fstr = "start_date parameter needs to be an instance of datetime" raise LCError(fstr) if end_date is not None and not isinstance(end_date, datetime.datetime): fstr = "end_date parameter needs to be an instance of datetime" raise LCError(fstr) if amount <= 0.0: fstr = "amount has to be a positive number for transfer" raise LCError(fstr) payload = { 'transferFrequency': frequency.value, 'amount': amount, } if start_date is not None: payload['startDate'] = start_date.isoformat() if end_date is not None: payload['endDate'] = end_date.isoformat() return Response(request.post(url, json=payload))
def search(self, filter_id=None, show_all=None): """ Apply filters and search for loans matching the specifications """ url = DNS + ENDPOINTS['loans'].format(version=API_VERSION) criteria = list() if filter_id is not None: criteria.append('filterId={}'.format(filter_id)) if show_all is not None: if show_all: criteria.append('showAll=true') else: criteria.append('showAll=false') if criteria: url += '?' + '&'.join(criteria) headers = {'X-LC-LISTING-VERSION': LISTING_VERSION} response = Response(request.get(url, headers=headers)) if not response.successful: fstr = "cannot search for any loans" raise LCError(fstr, details=json.dumps(response.json, indent=2)) # Reset the stored loans whenever we search again as long as the # latest request was successful self.loans = list() for loan_json in response.json['loans']: loan = Loan(loan_json) self.loans.append(loan)
def pending(investor_id): """ Retrieve the pending transfers :param investor_id: int - the investor account id :returns: iterable of instance of lendingclub2.response.transfer.Transaction """ url = DNS + ENDPOINTS['pending_transfer'].format(version=API_VERSION, investor_id=investor_id) response = Response(request.get(url)) if not response.successful: fstr = "cannot find list of pending transactions" raise LCError(fstr, details=json.dumps(response.json, indent=2)) transactions = list() total_transactions = 0 try: total_transactions = response.json['transfers'] except KeyError: pass for key in range(total_transactions): transactions.append(Transaction(response.json[key])) return transactions
def __init__(self, loan_id, amount, portfolio_id=None): """ Constructor :param loan_id: int :param amount: float - must be greater than 0 (usually 25) :param portfolio_id: int - portfolio ID which the note will be assigned to if the order is submitted successfully """ if amount <= 0: fstr = "amount should be a positive number" raise LCError(fstr) if amount % 25 != 0: fstr = "amount needs to be a multiple of $25" raise LCError(fstr) self._loan_id = loan_id self._amount = amount self._portfolio_id = portfolio_id
def __init__(self, percentage): """ Constructor. :param percentage: float (between 0 and 100 inclusive) """ if percentage < 0.0 or percentage > 100.0: fstr = "percentage needs to be between 0 and 100 (inclusive)" raise LCError(fstr) self._percentage = percentage
def invest(self, *order_notes): """ Invest to loans as specified. :param order_notes: iterable of instance of :py:class:`~lendingclub2.response.order.OrderNote`. """ order = Order(self.id(), *order_notes) if not order.successful: fstr = "could not complete the request completely" raise LCError(fstr)
def get_config_content(): """ Read the configuration file content. :returns: instance of :py:class:`configparser.ConfigParser`. """ fpath = get_config_fpath() if not os.path.exists(fpath): fstr = "expected configuration path doesn't exist: " + fpath raise LCError(fstr) config = ConfigParser() with open(fpath) as fin: config.read_file(fin) return config
def __init__(self, traits): """ Constructor :param traits: instance of lendingclub2.filter.BorrowerTrait or iterable of instance of lendingclub2.filter.BorrowerTrait """ if isinstance(traits, collections.Iterable): self._specs = traits elif isinstance(traits, BorrowerTrait): self._specs = (traits, ) else: fstr = "invalid traits type for {}".format(self.__class__.__name__) raise LCError(fstr)
def __init__(self): """ Constructor """ if Authorization._CODE is not None: return if os.getenv(API_KEY_ENV): Authorization._CODE = os.getenv(API_KEY_ENV) else: config = utils.get_config_content() try: Authorization._CODE = config['access']['api_key'] except KeyError as exc: fstr = "configuration file doesn't have info about api_key" raise LCError(fstr) from exc
def id(cls): """ Get the account ID. :returns: string """ if cls._ID is None: if os.getenv(INVESTOR_ID_ENV): cls._ID = os.getenv(INVESTOR_ID_ENV) else: config = utils.get_config_content() try: cls._ID = config['account']['investor_id'] except KeyError as exc: fstr = "cannot find the information of the investor ID" raise LCError(fstr, hint=str(exc)) return cls._ID
def withdraw(investor_id, amount): """ Withdraw the account :param investor_id: int - the investor account id :param amount: float - amount to withdraw :returns: instance of lendingclub2.response.Response """ url = DNS + ENDPOINTS['withdraw'].format(version=API_VERSION, investor_id=investor_id) if amount <= 0.0: fstr = "amount has to be a positive number for withdrawal" raise LCError(fstr) payload = {'amount': amount} return Response(request.post(url, json=payload))
def post(*args, **kwargs): """ Wrapper around :py:func:`requests.post` function. :param args: tuple - positional arguments for :py:func:`requests.post`. :param kwargs: dict - keyword arguments for :py:func:`requests.post`. :returns: instance of :py:class:`requests.Response`. """ global __LAST_REQUEST_TIMESTAMP __add_headers_to_kwargs(kwargs) __wait_request() try: response = requests.post(*args, **kwargs) __LAST_REQUEST_TIMESTAMP = datetime.datetime.now() return response except requests.ConnectionError as exc: fstr = "Cannot connect correctly" raise LCError(fstr) from exc
def get(*args, **kwargs): """ Wrapper around requests.get function. :param args: tuple - positional arguments for requests.get :param kwargs: dict - keyword arguments for requests.get :returns: instance of requests.Response """ global __LAST_REQUEST_TIMESTAMP __add_headers_to_kwargs(kwargs) __wait_request() try: response = requests.get(*args, **kwargs) __LAST_REQUEST_TIMESTAMP = datetime.datetime.now() return response except requests.ConnectionError as exc: fstr = "Cannot connect correctly" raise LCError(fstr, details=str(exc))