wbportfolio 1.55.4__py2.py3-none-any.whl → 1.55.6__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of wbportfolio might be problematic. Click here for more details.
- wbportfolio/analysis/claims.py +5 -6
- wbportfolio/filters/assets.py +8 -1
- wbportfolio/import_export/handlers/asset_position.py +12 -4
- wbportfolio/import_export/parsers/sg_lux/equity.py +5 -6
- wbportfolio/tests/analysis/__init__.py +0 -0
- wbportfolio/tests/analysis/test_claims.py +85 -0
- {wbportfolio-1.55.4.dist-info → wbportfolio-1.55.6.dist-info}/METADATA +1 -1
- {wbportfolio-1.55.4.dist-info → wbportfolio-1.55.6.dist-info}/RECORD +10 -8
- {wbportfolio-1.55.4.dist-info → wbportfolio-1.55.6.dist-info}/WHEEL +0 -0
- {wbportfolio-1.55.4.dist-info → wbportfolio-1.55.6.dist-info}/licenses/LICENSE +0 -0
wbportfolio/analysis/claims.py
CHANGED
|
@@ -58,13 +58,12 @@ class ConsolidatedTradeSummary:
|
|
|
58
58
|
self.pivot_label = pivot_label
|
|
59
59
|
self.queryset = self.queryset.annotate(
|
|
60
60
|
internal_trade=F("trade__marked_as_internal"),
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
),
|
|
61
|
+
valid_date=Greatest("trade__transaction_date", "date"),
|
|
62
|
+
date_considered=ExpressionWrapper(F("valid_date") + 1, output_field=DateField()),
|
|
64
63
|
net_value=InstrumentPrice.subquery_closest_value(
|
|
65
|
-
"net_value", date_name="
|
|
64
|
+
"net_value", date_name="valid_date", instrument_pk_name="product__pk", date_lookup="exact"
|
|
66
65
|
),
|
|
67
|
-
fx_rate=CurrencyFXRates.get_fx_rates_subquery("
|
|
66
|
+
fx_rate=CurrencyFXRates.get_fx_rates_subquery("valid_date", lookup_expr="exact"),
|
|
68
67
|
aum=ExpressionWrapper(F("fx_rate") * F("net_value") * F("shares"), output_field=DecimalField()),
|
|
69
68
|
)
|
|
70
69
|
self.queryset = Account.annotate_root_account_info(self.queryset)
|
|
@@ -158,8 +157,8 @@ class ConsolidatedTradeSummary:
|
|
|
158
157
|
df = df.fillna(0)
|
|
159
158
|
# Prepare dataframe
|
|
160
159
|
df["sum_aum_start"] = df.sum_shares_start * df.price_start
|
|
161
|
-
df["sum_aum_end"] = df.sum_shares_end * df.price_end
|
|
162
160
|
|
|
161
|
+
df["sum_aum_end"] = df.sum_shares_end * df.price_end
|
|
163
162
|
# Sanitize dataframe
|
|
164
163
|
df = df.drop(
|
|
165
164
|
columns=df.columns.difference(["id", "sum_shares_start", "sum_shares_end", "sum_aum_start", "sum_aum_end"])
|
wbportfolio/filters/assets.py
CHANGED
|
@@ -127,7 +127,7 @@ class AssetPositionFilter(wb_filters.FilterSet):
|
|
|
127
127
|
)
|
|
128
128
|
|
|
129
129
|
underlying_instrument__is_cash = wb_filters.BooleanFilter(
|
|
130
|
-
label="
|
|
130
|
+
label="Cash", lookup_expr="exact", method="filter_is_cash"
|
|
131
131
|
)
|
|
132
132
|
underlying_instrument__instrument_type = wb_filters.ModelChoiceFilter(
|
|
133
133
|
label="Instrument Type",
|
|
@@ -230,6 +230,13 @@ class AssetPositionFilter(wb_filters.FilterSet):
|
|
|
230
230
|
return queryset.filter(underlying_instrument__in=value.get_classified_instruments())
|
|
231
231
|
return queryset
|
|
232
232
|
|
|
233
|
+
def filter_is_cash(self, queryset, name, value):
|
|
234
|
+
if value is True:
|
|
235
|
+
return queryset.filter(Q(underlying_quote__is_cash=True) | Q(underlying_quote__is_cash_equivalent=True))
|
|
236
|
+
if value is False:
|
|
237
|
+
return queryset.filter(Q(underlying_quote__is_cash=False) & Q(underlying_quote__is_cash_equivalent=False))
|
|
238
|
+
return queryset
|
|
239
|
+
|
|
233
240
|
def filter_portfolio_instrument(self, queryset, name, value):
|
|
234
241
|
if value:
|
|
235
242
|
return queryset.filter(
|
|
@@ -9,7 +9,8 @@ from django.core.exceptions import ObjectDoesNotExist
|
|
|
9
9
|
from django.db import models
|
|
10
10
|
from wbcore.contrib.authentication.authentication import User
|
|
11
11
|
from wbcore.contrib.currency.import_export.handlers import CurrencyImportHandler
|
|
12
|
-
from wbcore.contrib.
|
|
12
|
+
from wbcore.contrib.currency.models import Currency
|
|
13
|
+
from wbcore.contrib.io.exceptions import DeserializationError, SkipImportError
|
|
13
14
|
from wbcore.contrib.io.imports import ImportExportHandler
|
|
14
15
|
from wbcore.contrib.notifications.dispatch import send_notification
|
|
15
16
|
from wbfdm.import_export.handlers.instrument import InstrumentImportHandler
|
|
@@ -36,9 +37,13 @@ class AssetPositionImportHandler(ImportExportHandler):
|
|
|
36
37
|
portfolio_data = data.pop("portfolio", None)
|
|
37
38
|
underlying_quote_data = data.pop("underlying_quote", data.pop("underlying_instrument", None))
|
|
38
39
|
if "currency" in data:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
currency = self.currency_handler.process_object(data["currency"], read_only=True, raise_exception=False)[0]
|
|
41
|
+
# we do not support GBX in our instrument table
|
|
42
|
+
if currency.key == "GBX":
|
|
43
|
+
currency = Currency.objects.get(key="GBP")
|
|
44
|
+
if "initial_price" in data:
|
|
45
|
+
data["initial_price"] /= 1000
|
|
46
|
+
data["currency"] = currency
|
|
42
47
|
data["date"] = datetime.strptime(data["date"], "%Y-%m-%d").date()
|
|
43
48
|
if data.get("asset_valuation_date", None):
|
|
44
49
|
data["asset_valuation_date"] = datetime.strptime(data["asset_valuation_date"], "%Y-%m-%d").date()
|
|
@@ -83,6 +88,9 @@ class AssetPositionImportHandler(ImportExportHandler):
|
|
|
83
88
|
if not (value := data.get(field, None)) is None:
|
|
84
89
|
data[field] = Decimal(value)
|
|
85
90
|
|
|
91
|
+
if data["weighting"] == 0:
|
|
92
|
+
raise SkipImportError("exclude position whose weight is 0")
|
|
93
|
+
|
|
86
94
|
def _process_raw_data(self, data: Dict[str, Any]):
|
|
87
95
|
if prices := data.get("prices", None):
|
|
88
96
|
self.import_source.log += "Instrument Prices found: Importing"
|
|
@@ -82,7 +82,7 @@ def parse(import_source):
|
|
|
82
82
|
cash = (
|
|
83
83
|
df.loc[
|
|
84
84
|
cash_mask,
|
|
85
|
-
["currency__key", "initial_currency_fx_rate", "portfolio", "date", "
|
|
85
|
+
["currency__key", "initial_currency_fx_rate", "portfolio", "date", "initial_shares"],
|
|
86
86
|
]
|
|
87
87
|
.groupby(
|
|
88
88
|
[
|
|
@@ -94,21 +94,20 @@ def parse(import_source):
|
|
|
94
94
|
.agg(
|
|
95
95
|
{
|
|
96
96
|
"initial_currency_fx_rate": "mean",
|
|
97
|
-
"initial_price": "mean",
|
|
98
97
|
"initial_shares": "sum",
|
|
99
98
|
}
|
|
100
99
|
)
|
|
101
100
|
.reset_index()
|
|
102
101
|
).copy()
|
|
103
102
|
cash["underlying_quote"] = cash["currency__key"].apply(lambda x: {"currency__key": x, "instrument_type": "cash"})
|
|
104
|
-
|
|
103
|
+
cash["initial_price"] = 1.0
|
|
105
104
|
# cash_equivalents_mask, all asset type code that match TRES and which don't have accounting category T111
|
|
106
105
|
cash_equivalents_mask = df["Asset type code"].str.match("TRES") & ~df["Accounting category"].str.match("T111")
|
|
107
106
|
|
|
108
107
|
cash_equivalents = (
|
|
109
108
|
df.loc[
|
|
110
109
|
cash_equivalents_mask,
|
|
111
|
-
["currency__key", "initial_currency_fx_rate", "portfolio", "date", "
|
|
110
|
+
["currency__key", "initial_currency_fx_rate", "portfolio", "date", "initial_shares"],
|
|
112
111
|
]
|
|
113
112
|
.groupby(
|
|
114
113
|
[
|
|
@@ -120,7 +119,6 @@ def parse(import_source):
|
|
|
120
119
|
.agg(
|
|
121
120
|
{
|
|
122
121
|
"initial_currency_fx_rate": "mean",
|
|
123
|
-
"initial_price": "mean",
|
|
124
122
|
"initial_shares": "sum",
|
|
125
123
|
}
|
|
126
124
|
)
|
|
@@ -129,9 +127,11 @@ def parse(import_source):
|
|
|
129
127
|
cash_equivalents["underlying_quote"] = cash_equivalents["currency__key"].apply(
|
|
130
128
|
lambda x: {"currency__key": x, "instrument_type": "cash_equivalent"}
|
|
131
129
|
)
|
|
130
|
+
cash_equivalents["initial_price"] = 1.0
|
|
132
131
|
|
|
133
132
|
# equities = df.loc[df["Accounting category"].str.match("010"), :].copy() # Historically, we filter out equity base on the "accounting category" that matches "010", we had issue with equity having the code "020". We decided to use the column "Asset type code" and filter out with the code "VCOM"
|
|
134
133
|
equities = df.loc[df["Asset type code"].str.match("VMOB"), :].copy()
|
|
134
|
+
|
|
135
135
|
if not equities.empty:
|
|
136
136
|
equities["underlying_quote"] = equities.apply(lambda x: get_underlying_quote(x), axis=1)
|
|
137
137
|
equities["exchange"] = equities.apply(lambda x: get_exchange(x), axis=1)
|
|
@@ -140,7 +140,6 @@ def parse(import_source):
|
|
|
140
140
|
del equities["Bloom Ticker"]
|
|
141
141
|
del equities["Asset description"]
|
|
142
142
|
df = pd.concat([cash, equities, cash_equivalents])
|
|
143
|
-
|
|
144
143
|
df["asset_valuation_date"] = df["date"]
|
|
145
144
|
# Rename the columns
|
|
146
145
|
|
|
File without changes
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from datetime import date, timedelta
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from pandas._libs.tslibs.offsets import BDay
|
|
5
|
+
|
|
6
|
+
from wbportfolio.analysis.claims import ConsolidatedTradeSummary
|
|
7
|
+
from wbportfolio.models import Claim
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.mark.django_db
|
|
11
|
+
class TestConsolidatedTradeSummary:
|
|
12
|
+
def test_base(self, claim_factory, customer_trade_factory, product, instrument_price_factory):
|
|
13
|
+
d1 = date(2024, 1, 1)
|
|
14
|
+
d2 = date(2025, 1, 1)
|
|
15
|
+
p1 = instrument_price_factory.create(date=d1, instrument=product) # noqa
|
|
16
|
+
p2 = instrument_price_factory.create(date=d2, instrument=product)
|
|
17
|
+
t1 = customer_trade_factory.create(
|
|
18
|
+
shares=1000, transaction_date=d1, underlying_instrument=product, portfolio=product.primary_portfolio
|
|
19
|
+
)
|
|
20
|
+
t2 = customer_trade_factory.create(
|
|
21
|
+
shares=500, transaction_date=d2, underlying_instrument=product, portfolio=product.primary_portfolio
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
c0 = claim_factory.create() # noqa
|
|
25
|
+
c1 = claim_factory.create(shares=1000, status="APPROVED", trade=t1, date=d2, product=product)
|
|
26
|
+
c2 = claim_factory.create(shares=500, status="APPROVED", trade=t2, date=d1, product=product)
|
|
27
|
+
cts = ConsolidatedTradeSummary(Claim.objects.all(), d1, d2, "account", "account__title")
|
|
28
|
+
|
|
29
|
+
valid_date = dict(cts.queryset.values_list("id", "valid_date"))
|
|
30
|
+
assert valid_date == {c1.id: d2, c2.id: d2}
|
|
31
|
+
|
|
32
|
+
date_considered = dict(cts.queryset.values_list("id", "date_considered"))
|
|
33
|
+
assert date_considered == {c1.id: d2 + timedelta(days=1), c2.id: d2 + timedelta(days=1)}
|
|
34
|
+
|
|
35
|
+
aum = dict(cts.queryset.values_list("id", "aum"))
|
|
36
|
+
assert aum == {c1.id: p2.net_value * c1.shares, c2.id: p2.net_value * c2.shares}
|
|
37
|
+
|
|
38
|
+
def test_get_aum_df(self, claim_factory, product, instrument_price_factory, customer_trade_factory):
|
|
39
|
+
t1 = customer_trade_factory.create(
|
|
40
|
+
shares=10,
|
|
41
|
+
transaction_date=date(2024, 12, 31),
|
|
42
|
+
underlying_instrument=product,
|
|
43
|
+
portfolio=product.primary_portfolio,
|
|
44
|
+
)
|
|
45
|
+
t2 = customer_trade_factory.create(
|
|
46
|
+
shares=100,
|
|
47
|
+
transaction_date=date(2025, 2, 3),
|
|
48
|
+
underlying_instrument=product,
|
|
49
|
+
portfolio=product.primary_portfolio,
|
|
50
|
+
)
|
|
51
|
+
c1 = claim_factory.create(trade=t1, status="APPROVED")
|
|
52
|
+
c2 = claim_factory.create(trade=t2, status="APPROVED", account=c1.account)
|
|
53
|
+
d1 = date(2025, 1, 1)
|
|
54
|
+
d2 = date(2025, 3, 3)
|
|
55
|
+
product.prices.all().delete()
|
|
56
|
+
p1 = instrument_price_factory.create(
|
|
57
|
+
date=(d1 - BDay(7)).date(), instrument=product
|
|
58
|
+
) # we test that the CTS uses the earliest date
|
|
59
|
+
p2 = instrument_price_factory.create(date=c2.date, instrument=product) # noqa
|
|
60
|
+
p3 = instrument_price_factory.create(date=d2, instrument=product)
|
|
61
|
+
|
|
62
|
+
cts = ConsolidatedTradeSummary(Claim.objects.all(), d1, d2, "account", "account__title")
|
|
63
|
+
aum_start = float(round(p1.net_value * c1.shares))
|
|
64
|
+
aum_end = float(round(p3.net_value * (c1.shares + c2.shares)))
|
|
65
|
+
assert cts.get_aum_df().to_dict(orient="index") == {
|
|
66
|
+
c1.account.id: {
|
|
67
|
+
"sum_shares_start": c1.shares,
|
|
68
|
+
"sum_shares_end": c1.shares + c2.shares,
|
|
69
|
+
"sum_aum_start": aum_start,
|
|
70
|
+
"sum_aum_end": aum_end,
|
|
71
|
+
"sum_shares_diff": c2.shares,
|
|
72
|
+
"sum_shares_perf": (c1.shares + c2.shares) / c1.shares - 1,
|
|
73
|
+
"sum_aum_diff": aum_end - aum_start,
|
|
74
|
+
"sum_aum_perf": aum_end / aum_start - 1,
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
p0 = instrument_price_factory.create(date=c1.date, instrument=product) # noqa
|
|
79
|
+
|
|
80
|
+
assert cts.get_nnm_df().to_dict(orient="index") == {
|
|
81
|
+
c1.account.id: {
|
|
82
|
+
"sum_nnm_2025-02": float(round(c2.shares * p2.net_value)),
|
|
83
|
+
"sum_nnm_total": float(round(c2.shares * p2.net_value)),
|
|
84
|
+
}
|
|
85
|
+
}, "Ensure the first claim that is considered in t+1 (on the CTS lower bound range) is excluded from the NNM"
|
|
@@ -28,7 +28,7 @@ wbportfolio/admin/transactions/dividends.py,sha256=2Hx0yvcMp0VvzYfuO_jl-9KFrpq6R
|
|
|
28
28
|
wbportfolio/admin/transactions/fees.py,sha256=gpq-_k3ypEGVNuDfFE4OHtn-B9ZtkzA4YYNLtNu-Fc8,1329
|
|
29
29
|
wbportfolio/admin/transactions/trades.py,sha256=LanpSm6iaR9cmNvSJwpRFPkOgN46K_Y9YoMy0MReYuc,1913
|
|
30
30
|
wbportfolio/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
-
wbportfolio/analysis/claims.py,sha256=
|
|
31
|
+
wbportfolio/analysis/claims.py,sha256=wcTniEVdDnmME8LHrYbo-WWpQ5EzNPgAT2KJIGQ0IIA,10688
|
|
32
32
|
wbportfolio/api_clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
wbportfolio/api_clients/ubs.py,sha256=pB_urTr8x8YCW28c_hK7DeCzAx07VeLZ27TamrZln2k,6598
|
|
34
34
|
wbportfolio/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -82,7 +82,7 @@ wbportfolio/factories/orders/orders.py,sha256=tTw2U-xvUsFpG4zad3KCHZPQx1FVg-zPjw
|
|
|
82
82
|
wbportfolio/fdm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
83
83
|
wbportfolio/fdm/tasks.py,sha256=59hXt3TOJaM8KpUaKdBNAGsO7NFMHaAlNA0T3FTUau0,533
|
|
84
84
|
wbportfolio/filters/__init__.py,sha256=m44CdyYMtku8rMGyiX8KSmMdvyqaElKW4UMkEqOC1VM,1374
|
|
85
|
-
wbportfolio/filters/assets.py,sha256=
|
|
85
|
+
wbportfolio/filters/assets.py,sha256=rvBNtQ8OcvYXSmaVdgjH7IITvaBZ558Y9sCj0B_WDpw,18866
|
|
86
86
|
wbportfolio/filters/assets_and_net_new_money_progression.py,sha256=IYl_qMFO9QKhXhCTtz2JrOjlAKdEkykNlu4DO_H7HkQ,1403
|
|
87
87
|
wbportfolio/filters/custodians.py,sha256=pStQgPQPhPpnt57_V7BuXbFXmRiZBEAiEeMFuQmt2NE,287
|
|
88
88
|
wbportfolio/filters/esg.py,sha256=ZEUQh3IQxLSshVrgtPqHC_ToirrllkCXR_KzUlCUtkA,688
|
|
@@ -120,7 +120,7 @@ wbportfolio/import_export/backends/wbfdm/dividend.py,sha256=iAQXnYPXmtG_Jrc8THAJ
|
|
|
120
120
|
wbportfolio/import_export/backends/wbfdm/mixin.py,sha256=JNtjgqGLson1nu_Chqb8MWyuiF3Ws8ox2vapxIRBYKE,400
|
|
121
121
|
wbportfolio/import_export/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
122
122
|
wbportfolio/import_export/handlers/adjustment.py,sha256=6bdTIYFmc8_HFxcdwtnYwglMyCfAD8XrTIrEb2zWY0g,1757
|
|
123
|
-
wbportfolio/import_export/handlers/asset_position.py,sha256=
|
|
123
|
+
wbportfolio/import_export/handlers/asset_position.py,sha256=LcJaHwxqoRWclBDOhaxTI7_MFqUXtUt99EJsV45ZqSo,9125
|
|
124
124
|
wbportfolio/import_export/handlers/dividend.py,sha256=F0oLfNt2B_QQAjHBCRpxa5HSkfkAYdal_NjLJGtVckY,4408
|
|
125
125
|
wbportfolio/import_export/handlers/fees.py,sha256=BOFHAvSTlvVLaxnm6KD_fcza1TlPc02HOR9J0_jjswI,2495
|
|
126
126
|
wbportfolio/import_export/handlers/orders.py,sha256=GU3_tIy-tAw9aU-ifsnmMZPBB9sqfkFC_S1d9VziTwg,3136
|
|
@@ -161,7 +161,7 @@ wbportfolio/import_export/parsers/sg_lux/customer_trade.py,sha256=gTEUIaxlZvXXCg
|
|
|
161
161
|
wbportfolio/import_export/parsers/sg_lux/customer_trade_pending_slk.py,sha256=WyRpKXkNhpK4H9aNjW7_ggcCGlN_-9ETlR1QsE9xl_k,5068
|
|
162
162
|
wbportfolio/import_export/parsers/sg_lux/customer_trade_slk.py,sha256=D_1c0v6lTXkopjZzr9pQb575HxrMFe91tKk8xT1X3Ns,3604
|
|
163
163
|
wbportfolio/import_export/parsers/sg_lux/customer_trade_without_pw.py,sha256=nMYV9-OwY_TagU36Ab0dOweZYzVriFWHXPYjauBg2Yk,2034
|
|
164
|
-
wbportfolio/import_export/parsers/sg_lux/equity.py,sha256=
|
|
164
|
+
wbportfolio/import_export/parsers/sg_lux/equity.py,sha256=IRwjeQmNFGuALUCWpWXWtflUEjl5qKyJumlQIAHmOPk,6076
|
|
165
165
|
wbportfolio/import_export/parsers/sg_lux/fees.py,sha256=AK2TGOjI3JrOjtACEQd-4ffuedtIus-_gWug6wN6RQs,1846
|
|
166
166
|
wbportfolio/import_export/parsers/sg_lux/perf_fees.py,sha256=6HAV3Pu2aaYARjMQvN24Op2rru_YdjeI9J9ADDQVH8s,1513
|
|
167
167
|
wbportfolio/import_export/parsers/sg_lux/portfolio_cash_flow.py,sha256=ftLKWukUl9AcGWHQmJZnShVZpkO4rOl04PGlLcalDdQ,889
|
|
@@ -399,6 +399,8 @@ wbportfolio/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
|
399
399
|
wbportfolio/tests/conftest.py,sha256=007ydJK59J1guakXWYrZ-waDZNgXAXwMYSJ-BTDFVhA,4614
|
|
400
400
|
wbportfolio/tests/signals.py,sha256=aUu4nDWmVAAWyokcWJDj2RsajeIa070qXsZeNq6ynqY,5545
|
|
401
401
|
wbportfolio/tests/tests.py,sha256=3NdpJQlksLclF-7lVP07WJXaEzquhneoDX1lIA_tyXU,1121
|
|
402
|
+
wbportfolio/tests/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
403
|
+
wbportfolio/tests/analysis/test_claims.py,sha256=aWiYASn7sLg255Bq38kUd9skpYQKxnROUKau6ha4uww,4036
|
|
402
404
|
wbportfolio/tests/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
403
405
|
wbportfolio/tests/models/test_account_reconciliation.py,sha256=7IDZh6qbG7-3czbNf5aDRaEDnMBw2Qiqk_h425dFu9w,8569
|
|
404
406
|
wbportfolio/tests/models/test_assets.py,sha256=N8OP2ZTPdq0lGonFRB0q_ruwF8QYpOGLkPWoucr8u_E,10428
|
|
@@ -565,7 +567,7 @@ wbportfolio/viewsets/transactions/claim.py,sha256=Pb1WftoO-w-ZSTbLRhmQubhy7hgd68
|
|
|
565
567
|
wbportfolio/viewsets/transactions/fees.py,sha256=WT2bWWfgozz4_rpyTKX7dgBBTXD-gu0nlsd2Nk2Zh1Q,7028
|
|
566
568
|
wbportfolio/viewsets/transactions/mixins.py,sha256=WipvJoi5hylkpD0y9VATe30WAcwIHUIroVkK10FYw7k,636
|
|
567
569
|
wbportfolio/viewsets/transactions/trades.py,sha256=xBgOGaJ8aEg-2RxEJ4FDaBs4SGwuLasun3nhpis0WQY,12363
|
|
568
|
-
wbportfolio-1.55.
|
|
569
|
-
wbportfolio-1.55.
|
|
570
|
-
wbportfolio-1.55.
|
|
571
|
-
wbportfolio-1.55.
|
|
570
|
+
wbportfolio-1.55.6.dist-info/METADATA,sha256=WQr-aAydWkUH5Imfj_Z7qYO0nnGFfT_NdCUQuTFAyvQ,751
|
|
571
|
+
wbportfolio-1.55.6.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
|
|
572
|
+
wbportfolio-1.55.6.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
|
|
573
|
+
wbportfolio-1.55.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|