GR
This commit is contained in:
@@ -68,6 +68,10 @@ def register():
|
||||
ctrm_reporting.CTRMRealizedPnlContext,
|
||||
ctrm_reporting.CTRMMtmPnl,
|
||||
ctrm_reporting.CTRMMtmPnlContext,
|
||||
ctrm_reporting.CTRMPnlExplain,
|
||||
ctrm_reporting.CTRMPnlExplainContext,
|
||||
ctrm_reporting.CTRMPnlDimension,
|
||||
ctrm_reporting.CTRMPnlDimensionContext,
|
||||
configuration.Configuration,
|
||||
pricing.ImportPricesStart,
|
||||
pricing.ImportPricesResult,
|
||||
|
||||
@@ -555,3 +555,198 @@ class CTRMMtmPnl(ModelSQL, ModelView):
|
||||
'mtm_delta'),
|
||||
val.strategy.as_('strategy'),
|
||||
where=where)
|
||||
|
||||
|
||||
class CTRMPnlExplainContext(CTRMPnlContextMixin, ModelView):
|
||||
"CTRM P&L Explain Context"
|
||||
__name__ = 'ctrm.reporting.pnl.explain.context'
|
||||
|
||||
|
||||
class CTRMPnlExplain(ModelSQL, ModelView):
|
||||
"CTRM P&L Explain"
|
||||
__name__ = 'ctrm.reporting.pnl.explain'
|
||||
|
||||
valuation_date = fields.Date("Valuation Date")
|
||||
product = fields.Many2One('product.product', "Product")
|
||||
counterparty = fields.Many2One('party.party', "Counterparty")
|
||||
currency = fields.Many2One('currency.currency', "Currency")
|
||||
unit = fields.Many2One('product.uom', "Unit")
|
||||
state = fields.Char("State")
|
||||
strategy = fields.Many2One('mtm.strategy', "Strategy")
|
||||
physical_pnl = fields.Numeric("Physical P&L", digits=(16, 2))
|
||||
fee_pnl = fields.Numeric("Fee P&L", digits=(16, 2))
|
||||
derivative_pnl = fields.Numeric("Derivative P&L", digits=(16, 2))
|
||||
mtm_delta = fields.Numeric("MTM Delta", digits=(16, 2))
|
||||
total_pnl = fields.Numeric("Total P&L", digits=(16, 2))
|
||||
|
||||
@classmethod
|
||||
def table_query(cls):
|
||||
ValuationLine = Pool().get('valuation.valuation.line')
|
||||
val = ValuationLine.__table__()
|
||||
|
||||
context = Transaction().context
|
||||
where = val.type.in_(ALL_VALUATION_TYPES)
|
||||
if context.get('date'):
|
||||
where &= val.date == context['date']
|
||||
if context.get('product'):
|
||||
where &= val.product == context['product']
|
||||
if context.get('counterparty'):
|
||||
where &= val.counterparty == context['counterparty']
|
||||
if context.get('currency'):
|
||||
where &= val.currency == context['currency']
|
||||
if context.get('purchase'):
|
||||
where &= val.purchase == context['purchase']
|
||||
if context.get('sale'):
|
||||
where &= val.sale == context['sale']
|
||||
if context.get('strategy'):
|
||||
where &= val.strategy == context['strategy']
|
||||
if context.get('state'):
|
||||
where &= val.state == context['state']
|
||||
|
||||
is_fee = val.type.in_([
|
||||
'line fee',
|
||||
'pur. fee',
|
||||
'sale fee',
|
||||
'shipment fee',
|
||||
])
|
||||
is_derivative = val.type.in_(DERIVATIVE_VALUATION_TYPES)
|
||||
physical_pnl = Case(
|
||||
(is_fee | is_derivative, 0), else_=Coalesce(val.amount, 0))
|
||||
fee_pnl = Case((is_fee, Coalesce(val.amount, 0)), else_=0)
|
||||
derivative_pnl = Case(
|
||||
(is_derivative, Coalesce(val.amount, 0)), else_=0)
|
||||
mtm_delta = Coalesce(val.mtm, 0) - Coalesce(val.amount, 0)
|
||||
|
||||
group_by = [
|
||||
val.date,
|
||||
val.product,
|
||||
val.counterparty,
|
||||
val.currency,
|
||||
val.unit,
|
||||
val.state,
|
||||
val.strategy,
|
||||
]
|
||||
|
||||
return val.select(
|
||||
Literal(0).as_('create_uid'),
|
||||
CurrentTimestamp().as_('create_date'),
|
||||
Literal(None).as_('write_uid'),
|
||||
Literal(None).as_('write_date'),
|
||||
Min(val.id).as_('id'),
|
||||
val.date.as_('valuation_date'),
|
||||
val.product.as_('product'),
|
||||
val.counterparty.as_('counterparty'),
|
||||
val.currency.as_('currency'),
|
||||
val.unit.as_('unit'),
|
||||
val.state.as_('state'),
|
||||
val.strategy.as_('strategy'),
|
||||
Sum(physical_pnl).as_('physical_pnl'),
|
||||
Sum(fee_pnl).as_('fee_pnl'),
|
||||
Sum(derivative_pnl).as_('derivative_pnl'),
|
||||
Sum(mtm_delta).as_('mtm_delta'),
|
||||
Sum(Coalesce(val.amount, 0)).as_('total_pnl'),
|
||||
where=where,
|
||||
group_by=group_by)
|
||||
|
||||
|
||||
class CTRMPnlDimensionContext(CTRMPnlContextMixin, ModelView):
|
||||
"CTRM P&L by Dimension Context"
|
||||
__name__ = 'ctrm.reporting.pnl.dimension.context'
|
||||
|
||||
dimension = fields.Many2One('analytic.dimension', "Dimension")
|
||||
value = fields.Many2One('analytic.dimension.value', "Value")
|
||||
|
||||
|
||||
class CTRMPnlDimension(ModelSQL, ModelView):
|
||||
"CTRM P&L by Dimension"
|
||||
__name__ = 'ctrm.reporting.pnl.dimension'
|
||||
|
||||
valuation_date = fields.Date("Valuation Date")
|
||||
dimension = fields.Many2One('analytic.dimension', "Dimension")
|
||||
value = fields.Many2One('analytic.dimension.value', "Value")
|
||||
product = fields.Many2One('product.product', "Product")
|
||||
counterparty = fields.Many2One('party.party', "Counterparty")
|
||||
currency = fields.Many2One('currency.currency', "Currency")
|
||||
unit = fields.Many2One('product.uom', "Unit")
|
||||
state = fields.Char("State")
|
||||
strategy = fields.Many2One('mtm.strategy', "Strategy")
|
||||
quantity = fields.Numeric("Quantity", digits=(16, 5))
|
||||
amount = fields.Numeric("Amount", digits=(16, 2))
|
||||
mtm = fields.Numeric("MTM", digits=(16, 2))
|
||||
mtm_delta = fields.Numeric("MTM Delta", digits=(16, 2))
|
||||
|
||||
@classmethod
|
||||
def table_query(cls):
|
||||
ValuationLine = Pool().get('valuation.valuation.line')
|
||||
Assignment = Pool().get('analytic.dimension.assignment')
|
||||
val = ValuationLine.__table__()
|
||||
purchase_assignment = Assignment.__table__()
|
||||
sale_assignment = Assignment.__table__()
|
||||
|
||||
context = Transaction().context
|
||||
dimension_expr = Coalesce(
|
||||
sale_assignment.dimension, purchase_assignment.dimension)
|
||||
value_expr = Coalesce(sale_assignment.value, purchase_assignment.value)
|
||||
|
||||
where = val.type.in_(ALL_VALUATION_TYPES)
|
||||
if context.get('date'):
|
||||
where &= val.date == context['date']
|
||||
if context.get('product'):
|
||||
where &= val.product == context['product']
|
||||
if context.get('counterparty'):
|
||||
where &= val.counterparty == context['counterparty']
|
||||
if context.get('currency'):
|
||||
where &= val.currency == context['currency']
|
||||
if context.get('purchase'):
|
||||
where &= val.purchase == context['purchase']
|
||||
if context.get('sale'):
|
||||
where &= val.sale == context['sale']
|
||||
if context.get('strategy'):
|
||||
where &= val.strategy == context['strategy']
|
||||
if context.get('state'):
|
||||
where &= val.state == context['state']
|
||||
if context.get('dimension'):
|
||||
where &= dimension_expr == context['dimension']
|
||||
if context.get('value'):
|
||||
where &= value_expr == context['value']
|
||||
|
||||
group_by = [
|
||||
val.date,
|
||||
dimension_expr,
|
||||
value_expr,
|
||||
val.product,
|
||||
val.counterparty,
|
||||
val.currency,
|
||||
val.unit,
|
||||
val.state,
|
||||
val.strategy,
|
||||
]
|
||||
|
||||
return (
|
||||
val
|
||||
.join(purchase_assignment, 'LEFT',
|
||||
condition=purchase_assignment.purchase == val.purchase)
|
||||
.join(sale_assignment, 'LEFT',
|
||||
condition=sale_assignment.sale == val.sale)
|
||||
.select(
|
||||
Literal(0).as_('create_uid'),
|
||||
CurrentTimestamp().as_('create_date'),
|
||||
Literal(None).as_('write_uid'),
|
||||
Literal(None).as_('write_date'),
|
||||
Min(val.id).as_('id'),
|
||||
val.date.as_('valuation_date'),
|
||||
dimension_expr.as_('dimension'),
|
||||
value_expr.as_('value'),
|
||||
val.product.as_('product'),
|
||||
val.counterparty.as_('counterparty'),
|
||||
val.currency.as_('currency'),
|
||||
val.unit.as_('unit'),
|
||||
val.state.as_('state'),
|
||||
val.strategy.as_('strategy'),
|
||||
Sum(Coalesce(val.quantity, 0)).as_('quantity'),
|
||||
Sum(Coalesce(val.amount, 0)).as_('amount'),
|
||||
Sum(Coalesce(val.mtm, 0)).as_('mtm'),
|
||||
Sum(Coalesce(val.mtm, 0) - Coalesce(val.amount, 0)).as_(
|
||||
'mtm_delta'),
|
||||
where=where,
|
||||
group_by=group_by))
|
||||
|
||||
@@ -100,6 +100,46 @@
|
||||
<field name="view" ref="ctrm_pnl_mtm_view_list"/>
|
||||
<field name="act_window" ref="act_ctrm_pnl_mtm"/>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="ctrm_pnl_explain_context_view_form">
|
||||
<field name="model">ctrm.reporting.pnl.explain.context</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">ctrm_pnl_explain_context_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="ctrm_pnl_explain_view_list">
|
||||
<field name="model">ctrm.reporting.pnl.explain</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">ctrm_pnl_explain_list</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window" id="act_ctrm_pnl_explain">
|
||||
<field name="name">P&L Explain</field>
|
||||
<field name="res_model">ctrm.reporting.pnl.explain</field>
|
||||
<field name="context_model">ctrm.reporting.pnl.explain.context</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_ctrm_pnl_explain_view">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="ctrm_pnl_explain_view_list"/>
|
||||
<field name="act_window" ref="act_ctrm_pnl_explain"/>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="ctrm_pnl_dimension_context_view_form">
|
||||
<field name="model">ctrm.reporting.pnl.dimension.context</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">ctrm_pnl_dimension_context_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="ctrm_pnl_dimension_view_list">
|
||||
<field name="model">ctrm.reporting.pnl.dimension</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">ctrm_pnl_dimension_list</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window" id="act_ctrm_pnl_dimension">
|
||||
<field name="name">P&L by Dimension</field>
|
||||
<field name="res_model">ctrm.reporting.pnl.dimension</field>
|
||||
<field name="context_model">ctrm.reporting.pnl.dimension.context</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_ctrm_pnl_dimension_view">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="ctrm_pnl_dimension_view_list"/>
|
||||
<field name="act_window" ref="act_ctrm_pnl_dimension"/>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
name="Positions"
|
||||
@@ -151,11 +191,13 @@
|
||||
name="P&L Explain"
|
||||
parent="menu_ctrm_pnl"
|
||||
sequence="30"
|
||||
action="act_ctrm_pnl_explain"
|
||||
id="menu_ctrm_pnl_explain"/>
|
||||
<menuitem
|
||||
name="P&L by Dimension"
|
||||
parent="menu_ctrm_pnl"
|
||||
sequence="40"
|
||||
action="act_ctrm_pnl_dimension"
|
||||
id="menu_ctrm_pnl_dimension"/>
|
||||
|
||||
<menuitem
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<form>
|
||||
<label name="date"/>
|
||||
<field name="date"/>
|
||||
<label name="dimension"/>
|
||||
<field name="dimension"/>
|
||||
<label name="value"/>
|
||||
<field name="value"/>
|
||||
<label name="product"/>
|
||||
<field name="product"/>
|
||||
<label name="counterparty"/>
|
||||
<field name="counterparty"/>
|
||||
<label name="currency"/>
|
||||
<field name="currency"/>
|
||||
<label name="purchase"/>
|
||||
<field name="purchase"/>
|
||||
<label name="sale"/>
|
||||
<field name="sale"/>
|
||||
<label name="strategy"/>
|
||||
<field name="strategy"/>
|
||||
<label name="state"/>
|
||||
<field name="state"/>
|
||||
</form>
|
||||
14
modules/purchase_trade/view/ctrm_pnl_dimension_list.xml
Normal file
14
modules/purchase_trade/view/ctrm_pnl_dimension_list.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<tree>
|
||||
<field name="valuation_date"/>
|
||||
<field name="dimension" width="120"/>
|
||||
<field name="value" width="140"/>
|
||||
<field name="product" width="140"/>
|
||||
<field name="counterparty" width="120"/>
|
||||
<field name="state"/>
|
||||
<field name="strategy"/>
|
||||
<field name="quantity" symbol="unit" sum="1"/>
|
||||
<field name="currency" width="60"/>
|
||||
<field name="amount" sum="1"/>
|
||||
<field name="mtm" sum="1"/>
|
||||
<field name="mtm_delta" sum="1"/>
|
||||
</tree>
|
||||
@@ -0,0 +1,18 @@
|
||||
<form>
|
||||
<label name="date"/>
|
||||
<field name="date"/>
|
||||
<label name="product"/>
|
||||
<field name="product"/>
|
||||
<label name="counterparty"/>
|
||||
<field name="counterparty"/>
|
||||
<label name="currency"/>
|
||||
<field name="currency"/>
|
||||
<label name="purchase"/>
|
||||
<field name="purchase"/>
|
||||
<label name="sale"/>
|
||||
<field name="sale"/>
|
||||
<label name="strategy"/>
|
||||
<field name="strategy"/>
|
||||
<label name="state"/>
|
||||
<field name="state"/>
|
||||
</form>
|
||||
13
modules/purchase_trade/view/ctrm_pnl_explain_list.xml
Normal file
13
modules/purchase_trade/view/ctrm_pnl_explain_list.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<tree>
|
||||
<field name="valuation_date"/>
|
||||
<field name="product" width="140"/>
|
||||
<field name="counterparty" width="120"/>
|
||||
<field name="state"/>
|
||||
<field name="strategy"/>
|
||||
<field name="currency" width="60"/>
|
||||
<field name="physical_pnl" sum="1"/>
|
||||
<field name="fee_pnl" sum="1"/>
|
||||
<field name="derivative_pnl" sum="1"/>
|
||||
<field name="mtm_delta" sum="1"/>
|
||||
<field name="total_pnl" sum="1"/>
|
||||
</tree>
|
||||
@@ -34,3 +34,12 @@ Date: 2026-05-24
|
||||
- toutes les lignes valorisees.
|
||||
- `Mark-to-Market` lit la derniere valuation et compare `mtm` a `amount`
|
||||
via une colonne `MTM Delta`.
|
||||
- `P&L Explain` decompose le P&L en blocs auditables:
|
||||
- physical;
|
||||
- fees;
|
||||
- derivatives;
|
||||
- MTM delta.
|
||||
- `P&L by Dimension` joint les dimensions analytiques portees par les achats
|
||||
et ventes. Si un contrat porte plusieurs dimensions, une ligne peut etre
|
||||
presente sur plusieurs axes; filtrer par dimension pour une analyse sans
|
||||
double comptage inter-axes.
|
||||
|
||||
Reference in New Issue
Block a user