Source code for woob.capabilities.bank.wealth
# Copyright(C) 2010-2016 Romain Bignon
#
# This file is part of woob.
#
# woob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# woob is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with woob. If not, see <http://www.gnu.org/licenses/>.
# flake8: compatible
from woob.capabilities.base import BaseObject, DecimalField, Enum, EnumField, Field, IntField, StringField
from woob.capabilities.date import DateField
from .base import Account, CapBank
__all__ = [
"PerVersion",
"PerProviderType",
"Per",
"Investment",
"Pocket",
"MarketOrderType",
"MarketOrderDirection",
"MarketOrderPayment",
"MarketOrder",
"CapBankWealth",
]
[docs]class PerVersion(Enum):
PERIN = "perin" # "PER individuel", subscribed by the account holder
PERCOL = "percol" # "PER collectif", subscribed by the employer for all employees
PERCAT = "percat" # "PER catégoriel", subscribed by the employer for a category of employees (for example managers)
[docs]class PerProviderType(Enum):
BANK = "bank"
INSURER = "insurer"
[docs]class Per(Account):
"""
Account type dedicated to PER retirement savings plans.
"""
version = EnumField("Version of PER", PerVersion)
provider_type = EnumField("Type of account provider", PerProviderType)
[docs]class Investment(BaseObject):
"""
Investment in a financial market.
"""
CODE_TYPE_ISIN = "ISIN"
CODE_TYPE_AMF = "AMF"
label = StringField("Label of stocks")
code = StringField("Identifier of the stock")
code_type = StringField("Type of stock code (ISIN or AMF)")
stock_symbol = StringField("Alternative identifier of the stock (different from ISIN)")
stock_market = StringField("Stock market related to the stock")
description = StringField("Short description of the stock")
quantity = DecimalField("Quantity of stocks")
unitprice = DecimalField("Buy price of one stock")
unitvalue = DecimalField("Current value of one stock")
valuation = DecimalField("Total current valuation of the Investment")
vdate = DateField("Value date of the valuation amount")
diff = DecimalField("Difference between the buy cost and the current valuation")
diff_ratio = DecimalField("Difference in ratio (1 meaning 100%) between the buy cost and the current valuation")
portfolio_share = DecimalField("Ratio (1 meaning 100%) of the current amount relative to the total")
performance_history = Field("History of the performances of the stock (key=years, value=diff_ratio)", dict)
srri = IntField("Synthetic Risk and Reward Indicator of the stock (from 1 to 7)")
asset_category = StringField("Category of the stock")
recommended_period = StringField("Recommended investment period of the stock")
# International
original_currency = StringField("Currency of the original amount")
original_valuation = DecimalField("Original valuation (in another currency)")
original_unitvalue = DecimalField("Original unitvalue (in another currency)")
original_unitprice = DecimalField("Original unitprice (in another currency)")
original_diff = DecimalField("Original diff (in another currency)")
def __repr__(self):
return f"<Investment label={self.label!r} code={self.code!r} valuation={self.valuation!r}>"
# compatibility alias
@property
def diff_percent(self):
return self.diff_ratio
@diff_percent.setter
def diff_percent(self, value):
self.diff_ratio = value
class PocketCondition(Enum):
UNKNOWN = 0
DATE = 1
# If 'availability_date' has passed
AVAILABLE = 2
RETIREMENT = 3
# the following conditions are used if :
# 'acquisition_date' and 'transferability_date' are displayed on the website.
# If 'acquisition_date' has not passed.
DATE_WHEN_ACQUIRED = 4
# If 'acquisition_date' has passed and 'transferability_date' has not.
DATE_WHEN_TRANSFERABLE = 5
# the following conditions are irrelevant, don't use them
WEDDING = 6
DEATH = 7
INDEBTEDNESS = 8
DIVORCE = 9
DISABILITY = 10
BUSINESS_CREATION = 11
BREACH_EMPLOYMENT_CONTRACT = 12
UNLOCKING_EXCEPTIONAL = 13
THIRD_CHILD = 14
EXPIRATION_UNEMPLOYMENT = 15
PURCHASE_APARTMENT = 16
[docs]class Pocket(BaseObject):
"""
Pocket
"""
CONDITION_UNKNOWN = PocketCondition.UNKNOWN
CONDITION_DATE = PocketCondition.DATE
CONDITION_DATE_WHEN_ACQUIRED = PocketCondition.DATE_WHEN_ACQUIRED
CONDITION_DATE_WHEN_TRANSFERABLE = PocketCondition.DATE_WHEN_TRANSFERABLE
CONDITION_AVAILABLE = PocketCondition.AVAILABLE
CONDITION_RETIREMENT = PocketCondition.RETIREMENT
# the following conditions are irrelevant, don't use them
CONDITION_WEDDING = PocketCondition.WEDDING
CONDITION_DEATH = PocketCondition.DEATH
CONDITION_INDEBTEDNESS = PocketCondition.INDEBTEDNESS
CONDITION_DIVORCE = PocketCondition.DIVORCE
CONDITION_DISABILITY = PocketCondition.DISABILITY
CONDITION_BUSINESS_CREATION = PocketCondition.BUSINESS_CREATION
CONDITION_BREACH_EMPLOYMENT_CONTRACT = PocketCondition.BREACH_EMPLOYMENT_CONTRACT
CONDITION_UNLOCKING_EXCEPTIONAL = PocketCondition.UNLOCKING_EXCEPTIONAL
CONDITION_THIRD_CHILD = PocketCondition.THIRD_CHILD
CONDITION_EXPIRATION_UNEMPLOYMENT = PocketCondition.EXPIRATION_UNEMPLOYMENT
CONDITION_PURCHASE_APARTMENT = PocketCondition.PURCHASE_APARTMENT
label = StringField("Label of pocket")
amount = DecimalField("Amount of the pocket")
quantity = DecimalField("Quantity of stocks")
availability_date = DateField("Availability date of the pocket")
condition = EnumField("Withdrawal condition of the pocket", PocketCondition, default=CONDITION_UNKNOWN)
investment = Field("Reference to the investment of the pocket", Investment)
[docs]class MarketOrderType(Enum):
UNKNOWN = 0
MARKET = 1
"""Order executed at the current market price"""
LIMIT = 2
"""Order executed with a maximum or minimum price limit"""
TRIGGER = 3
"""Order executed when the price reaches a specific value"""
[docs]class MarketOrderDirection(Enum):
UNKNOWN = 0
BUY = 1
SALE = 2
[docs]class MarketOrderPayment(Enum):
UNKNOWN = 0
CASH = 1
DEFERRED = 2
[docs]class MarketOrder(BaseObject):
"""
Market order
"""
# Important: a Market Order always corresponds to one (and only one) investment
label = StringField("Label of the market order")
# MarketOrder values
unitprice = DecimalField("Value of the stock at the moment of the market order")
unitvalue = DecimalField("Current value of the stock associated with the market order")
ordervalue = DecimalField("Limit value or trigger value, only relevant if the order type is LIMIT or TRIGGER")
currency = StringField("Currency of the market order - not always the same as account currency")
quantity = DecimalField("Quantity of stocks in the market order")
amount = DecimalField("Total amount that has been bought or sold")
# MarketOrder additional information
order_type = EnumField("Type of market order", MarketOrderType, default=MarketOrderType.UNKNOWN)
direction = EnumField(
"Direction of the market order (buy or sale)", MarketOrderDirection, default=MarketOrderDirection.UNKNOWN
)
payment_method = EnumField(
"Payment method of the market order", MarketOrderPayment, default=MarketOrderPayment.UNKNOWN
)
date = DateField("Creation date of the market order")
validity_date = DateField("Validity date of the market order")
execution_date = DateField("Execution date of the market order (only for market orders that are completed)")
state = StringField("Current state of the market order (e.g. executed)")
code = StringField("Identifier of the stock related to the order")
stock_symbol = StringField("Alternative identifier of the stock related to the order (different from ISIN)")
stock_market = StringField("Stock market on which the order was executed")
[docs]class CapBankWealth(CapBank):
"""
Capability of bank websites to see investments and pockets.
"""
[docs] def iter_investment(self, account):
"""
Iter investment of a market account
:param account: account to get investments
:type account: :class:`Account`
:rtype: iter[:class:`Investment`]
:raises: :class:`AccountNotFound`
"""
raise NotImplementedError()
[docs] def iter_pocket(self, account):
"""
Iter pocket
:param account: account to get pockets
:type account: :class:`Account`
:rtype: iter[:class:`Pocket`]
:raises: :class:`AccountNotFound`
"""
raise NotImplementedError()
[docs] def iter_market_orders(self, account):
"""
Iter market orders
:param account: account to get market orders
:type account: :class:`Account`
:rtype: iter[:class:`MarketOrder`]
:raises: :class:`AccountNotFound`
"""
raise NotImplementedError()