.. _quickstart:
Quick Start
===========
Get started with JACTUS in 5 minutes by creating your first financial contract.
Installation
------------
Install JACTUS using pip::
pip install jactus
Or for development::
git clone https://github.com/pedronahum/JACTUS.git
cd JACTUS
pip install -e ".[dev]"
Your First Contract
-------------------
Let's create a simple Principal at Maturity (PAM) contract - a 5-year interest-only loan.
Complete Example
^^^^^^^^^^^^^^^^
.. code-block:: python
from jactus.contracts import create_contract
from jactus.core import (
ContractAttributes,
ContractType,
ContractRole,
ActusDateTime,
DayCountConvention,
EndOfMonthConvention,
)
from jactus.observers import ConstantRiskFactorObserver
# Step 1: Define contract attributes
attrs = ContractAttributes(
contract_id="LOAN-001",
contract_type=ContractType.PAM,
contract_role=ContractRole.RPA, # Lender receives principal, pays interest
status_date=ActusDateTime(2024, 1, 1, 0, 0, 0),
initial_exchange_date=ActusDateTime(2024, 1, 1, 0, 0, 0),
maturity_date=ActusDateTime(2029, 1, 1, 0, 0, 0), # 5 years
notional_principal=100_000.0, # $100,000 loan
nominal_interest_rate=0.05, # 5% annual interest
day_count_convention=DayCountConvention.A360, # Actual/360
interest_payment_cycle="3M", # Quarterly payments
interest_payment_anchor=ActusDateTime(2024, 4, 1, 0, 0, 0),
end_of_month_convention=EndOfMonthConvention.SD, # Same day
currency="USD",
)
# Step 2: Create risk factor observer (fixed interest rate)
rf_observer = ConstantRiskFactorObserver(constant_value=0.05)
# Step 3: Create the contract
contract = create_contract(attrs, rf_observer)
# Step 4: Run simulation
result = contract.simulate()
print(f"Generated {len(result.events)} events")
# Step 5: Display payment schedule
print("\nPayment Schedule:")
print("-" * 60)
for event in result.events[:10]: # Show first 10 events
date = f"{event.event_time.year}-{event.event_time.month:02d}-{event.event_time.day:02d}"
print(f"{event.event_type.name:<6} {date:<12} ${event.payoff:>12,.2f}")
# Step 6: Analyze results
total_interest = sum(
event.payoff for event in result.events
if event.event_type.name == "IP"
)
print(f"\nTotal interest over 5 years: ${total_interest:,.2f}")
Expected Output
^^^^^^^^^^^^^^^
Running this example produces::
Generated 22 events
Payment Schedule:
------------------------------------------------------------
IED 2024-01-01 $0.00
IP 2024-04-01 $1,250.00
IP 2024-07-01 $1,250.00
IP 2024-10-01 $1,250.00
IP 2025-01-01 $1,250.00
IP 2025-04-01 $1,250.00
IP 2025-07-01 $1,250.00
IP 2025-10-01 $1,250.00
IP 2026-01-01 $1,250.00
IP 2026-04-01 $1,250.00
Total interest over 5 years: $25,000.00
Understanding the Code
----------------------
Contract Attributes
^^^^^^^^^^^^^^^^^^^
The ``ContractAttributes`` class defines all contract parameters:
* **contract_type**: The ACTUS contract type (PAM = Principal at Maturity)
* **contract_role**: Perspective (RPA = lender, RPL = borrower)
* **notional_principal**: The loan amount ($100,000)
* **nominal_interest_rate**: Annual interest rate (5% = 0.05)
* **interest_payment_cycle**: Payment frequency ("3M" = quarterly)
* **maturity_date**: When the principal is repaid
Risk Factor Observer
^^^^^^^^^^^^^^^^^^^^
The ``ConstantRiskFactorObserver`` provides market data (interest rates, FX rates, etc.)::
rf_observer = ConstantRiskFactorObserver(constant_value=0.05)
For fixed-rate contracts, this remains constant. For floating-rate contracts, use
``TimeSeriesRiskFactorObserver`` or ``DictRiskFactorObserver`` for varying rates.
SimulationHistory
^^^^^^^^^^^^^^^^^^
The ``simulate()`` method returns a ``SimulationHistory`` containing all events:
* **IED**: Initial Exchange Date (loan disbursement)
* **IP**: Interest Payment (quarterly interest payments)
* **MD**: Maturity Date (principal repayment)
Each event has:
* ``event_type``: Type of event (IED, IP, MD, etc.)
* ``event_time``: When the event occurs
* ``payoff``: Cash flow amount (positive = receive, negative = pay)
Simulation
^^^^^^^^^^
The ``simulate()`` method processes all events and returns a ``SimulationHistory``::
result = contract.simulate()
The simulation:
1. Starts with initial state
2. Processes each event in chronological order
3. Updates state variables at each event
4. Returns a ``SimulationHistory`` with ``events``, ``states``, ``initial_state``, and ``final_state``
Next Steps
----------
Explore More Examples
^^^^^^^^^^^^^^^^^^^^^
**Python Script Examples:**
All examples are in the ``examples/`` directory:
* ``pam_example.py`` - Principal at Maturity (bullet loans)
* ``lam_example.py`` - Linear Amortizer (equal principal payments)
* ``interest_rate_swap_example.py`` - Plain vanilla interest rate swap
* ``fx_swap_example.py`` - Foreign exchange swap
* ``cross_currency_basis_swap_example.py`` - Cross-currency basis swap
**Interactive Jupyter Notebooks:**
For hands-on learning, see the notebooks in ``examples/notebooks/``:
* ``01_annuity_mortgage.ipynb`` - ANN contract with 30-year mortgage visualization
* ``02_options_contracts.ipynb`` - OPTNS contracts with call/put payoff diagrams
* ``03_interest_rate_cap.ipynb`` - CAPFL contract with rate protection scenarios
* ``04_stock_commodity.ipynb`` - STK and COM contracts as derivative underliers
Try Different Contract Types
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
**Linear Amortizer (LAM)**::
attrs = ContractAttributes(
contract_type=ContractType.LAM,
# ... same basic parameters ...
principal_redemption_cycle="3M",
next_principal_redemption_amount=5_000.0, # $5k per quarter
)
**Interest Rate Swap (SWPPV)**::
attrs = ContractAttributes(
contract_type=ContractType.SWPPV,
# ... basic parameters ...
nominal_interest_rate=0.05, # Fixed leg
nominal_interest_rate_2=0.03, # Floating leg
interest_payment_cycle="3M",
rate_reset_cycle="3M",
)
**FX Outright (FXOUT)**::
attrs = ContractAttributes(
contract_type=ContractType.FXOUT,
currency="EUR",
currency_2="USD",
notional_principal=1_000_000.0, # EUR 1M
price_at_purchase_date=1.10, # Spot rate
)
Explore Time Features
^^^^^^^^^^^^^^^^^^^^^
JACTUS provides flexible time handling::
from jactus.core import ActusDateTime
# Create dates
start = ActusDateTime(2024, 1, 1, 0, 0, 0)
# Compare dates
if start < end:
print("Start before end")
# Calculate differences
from jactus.utilities.schedules import generate_schedule
dates = generate_schedule(
start=start,
end=end,
cycle="1M" # Monthly
)
Work with Schedules
^^^^^^^^^^^^^^^^^^^
Generate custom payment schedules::
from jactus.utilities.schedules import generate_schedule
schedule = generate_schedule(
start=ActusDateTime(2024, 1, 1, 0, 0, 0),
end=ActusDateTime(2029, 1, 1, 0, 0, 0),
cycle="3M" # Quarterly
)
for date in schedule:
print(date)
**Cycle Notation:**
* ``1D`` = Daily
* ``1W`` = Weekly
* ``1M`` = Monthly
* ``3M`` = Quarterly
* ``6M`` = Semi-annual
* ``1Y`` = Annual
Common Patterns
---------------
Monthly Mortgage Payment
^^^^^^^^^^^^^^^^^^^^^^^^
Calculate monthly payments on a loan::
attrs = ContractAttributes(
contract_type=ContractType.PAM,
notional_principal=300_000.0, # $300k
nominal_interest_rate=0.065, # 6.5%
interest_payment_cycle="1M", # Monthly
maturity_date=ActusDateTime(2054, 1, 1, 0, 0, 0), # 30 years
)
contract = create_contract(attrs, ConstantRiskFactorObserver(constant_value=0.065))
result = contract.simulate()
# Find monthly payment
ip_events = [e for e in result.events if e.event_type.name == "IP"]
monthly_payment = ip_events[0].payoff
print(f"Monthly payment: ${monthly_payment:,.2f}")
Analyzing Cash Flows
^^^^^^^^^^^^^^^^^^^^
Analyze different event types::
result = contract.simulate()
# Group by event type
events_by_type = {}
for event in result.events:
event_type = event.event_type.name
if event_type not in events_by_type:
events_by_type[event_type] = []
events_by_type[event_type].append(event)
# Calculate totals
for event_type, events in events_by_type.items():
total = sum(e.payoff for e in events)
print(f"{event_type}: {len(events)} events, ${total:,.2f} total")
Comparing Scenarios
^^^^^^^^^^^^^^^^^^^
Compare different interest rates::
rates = [0.03, 0.04, 0.05, 0.06, 0.07]
for rate in rates:
attrs.nominal_interest_rate = rate
contract = create_contract(attrs, ConstantRiskFactorObserver(constant_value=rate))
result = contract.simulate()
total_interest = sum(
e.payoff for e in result.events
if e.event_type.name == "IP"
)
print(f"Rate {rate*100:.1f}%: Total interest = ${total_interest:,.2f}")
Troubleshooting
---------------
Common Issues
^^^^^^^^^^^^^
**"ValueError: maturity_date is required"**
Make sure all required attributes are provided::
attrs = ContractAttributes(
contract_type=ContractType.PAM,
status_date=..., # Required
maturity_date=..., # Required
notional_principal=..., # Required
nominal_interest_rate=..., # Required for PAM
)
**"ValueError: Invalid cycle format"**
Use correct cycle notation::
# Correct
interest_payment_cycle="3M" # Quarterly
# Wrong
interest_payment_cycle="P3M" # Don't use 'P' prefix
interest_payment_cycle="3m" # Use uppercase 'M'
**"AttributeError: module has no attribute"**
Check imports::
# Correct
from jactus.core import ContractType
# Wrong
from jactus import ContractType # Not exported at top level
More Examples
-------------
JACTUS includes comprehensive examples:
* ``examples/pam_example.py`` - PAM contracts (mortgages, bonds)
* ``examples/lam_example.py`` - LAM contracts (amortizing loans)
* ``examples/interest_rate_swap_example.py`` - Interest rate swaps
* ``examples/fx_swap_example.py`` - FX swaps
* ``examples/cross_currency_basis_swap_example.py`` - Cross-currency swaps
Run an example::
python examples/pam_example.py
Further Reading
---------------
* :doc:`guides/index` - Comprehensive user guides
* :doc:`api/index` - Complete API reference
* :doc:`ARCHITECTURE` - System architecture
* :doc:`PAM` - Deep dive into PAM implementation
* :doc:`derivatives` - Derivative contracts guide
**External Resources:**
* `ACTUS Standard `_ - Official ACTUS specification
* `JAX Documentation `_ - JAX framework documentation
* `GitHub Repository `_ - Source code and issues
Need Help?
----------
* **Issues**: `GitHub Issues `_
* **Discussions**: `GitHub Discussions `_
* **Email**: pnrodriguezh@gmail.com
You're now ready to start modeling financial contracts with JACTUS!