riskparityportfolio

repository·main·Indexed 43 days ago

https://github.com/convexfi/riskparity.py

A Python library providing solvers for designing risk parity portfolios, supporting both simple convex formulations and complex nonconvex formulations using successive convex approximation (SCA).

Tokens
16.9K
Snippets
55
Records
69
Agent score
55%

What's inside riskparityportfolio

  1. Overview of riskparityportfolio solvers

    main

    The riskparityportfolio package provides solvers for designing risk parity portfolios using different mathematical formulations:

    • Convex Formulation: Implements the unique solution proposed by Spinu (2013) using cyclical methods inspired by Griveau-Billion et al. (2013) and Choi & Chen (2022).
    • General (Nonconvex) Formulations: Implements the Successive Convex Approximation (SCA) method proposed by Feng & Palomar (2015) to handle more complex, nonconvex optimization problems.
  2. Perform Scan Operations on Eigen Tensors

    main

    A Scan operation returns a tensor with the same dimensions as the original. It performs an inclusive scan along the specified axis, computing a running total (or product) for a given reduction operation.

    Available Scan Operations:

    • cumsum(axis): Performs a scan by summing consecutive entries (prefix sum).
    • cumprod(axis): Performs a scan by multiplying consecutive entries.
    // Create a tensor of 2 dimensions
    Eigen::Tensor<int, 2> a(2, 3);
    a.setValues({{1, 2, 3}, {4, 5, 6}});
    
    // Scan it along the second dimension (1) using summation
    Eigen::Tensor<int, 2> b = a.cumsum(1);
    // Result b:
    // 1  3  6
    // 4  9 15
  3. Understand lazy evaluation in Eigen Tensor operations

    main

    Eigen Tensor operations (like +, *, .exp()) use lazy evaluation. When you perform an operation, Eigen does not immediately compute the result. Instead, it constructs a lightweight "tensor operator" object (e.g., TensorCwiseBinaryOp) that represents the expression tree. The actual computation only occurs when the expression is assigned to a concrete storage type like Tensor, TensorFixedSize, or TensorMap.

    Tensor<float, 3> t1(2, 3, 4);
    Tensor<float, 3> t2(2, 3, 4);
    // t3 is NOT an operation; the addition happens here during assignment
    Tensor<float, 3> t3 = t1 + t2;
  4. Perform Tensor Operations with Lazy Evaluation

    main

    Eigen Tensor operations return non-evaluated Operations objects rather than immediate results. These operations can be chained together. The entire chain is evaluated lazily, typically only when the result is assigned to a tensor. This allows for efficient expression optimization.

    Constant and Random Tensors

    • constant(const Scalar& val): Returns a tensor of the same type and dimensions as the original, but with all elements set to val.
    • random(): Returns a tensor of the same type and dimensions as the original, but with all elements set to random values.
    Eigen::Tensor<float, 2> a(2, 3);
    a.setConstant(1.0f);
    Eigen::Tensor<float, 2> b = a + a.constant(2.0f);
    Eigen::Tensor<float, 2> c = b * b.constant(0.2f);
  5. Perform Reduction Operations on Eigen Tensors

    main

    A Reduction operation returns a tensor with fewer dimensions than the original by applying a reduction operator to slices of values. You specify the dimensions to reduce using an array of integers (the "reduction dimensions").

    Key Rules for Reduction Dimensions:

    • Dimensions are indices of the input tensor.
    • Each dimension index must be less than the tensor rank.
    • Each dimension should occur at most once in the reduction dimensions array.
    • Listing dimensions in increasing order may improve performance.
    • Special Case: If no parameter is passed to the reduction operation, the tensor is reduced along all dimensions, resulting in a zero-dimension tensor (a scalar).

    Common Reduction Operators:

    • sum(): Sum of reduced values.
    • mean(): Mean of reduced values.
    • maximum(): Largest of the reduced values.
    • minimum(): Smallest of the reduced values.
    • prod(): Product of the reduced values.
    • all(): Checks if all elements are true (after casting to bool).
    • any(): Checks if any element is true (after casting to bool).
    • reduce(dims, reducer): Uses a user-defined reduction operator.
    // Example: Reduction along one dimension
    Eigen::Tensor<int, 2> a(2, 3);
    a.setValues({{1, 2, 3}, {6, 5, 4}});
    Eigen::array<int, 1> dims({1}); // Reduce along the second dimension
    Eigen::Tensor<int, 1> b = a.maximum(dims);
    // b will be: 3, 6
    
    // Example: Reduction along all dimensions (returns a scalar/0-dim tensor)
    Eigen::Tensor<float, 3> a(2, 3, 4);
    Eigen::Tensor<float, 0> b = a.sum();
  6. Understand Eigen Tensor Datatypes

    main

    When working with Eigen Tensors, the documentation uses several specific pseudo-types to describe methods and operations:

    • <Tensor-Type>::Dimensions: An array-like object of ints representing the dimensions of a tensor. It has a .size attribute and supports indexing (e.g., d[0]).
    • <Tensor-Type>::Index: An integer type used for indexing tensors along their dimensions.
    • <Tensor-Type>::Scalar: The underlying data type of the individual tensor elements (e.g., float for Tensor<float, 2>).
    • <Operation>: Indicates that a method returns a deferred operation rather than a concrete tensor. You must evaluate an <Operation> (e.g., by assigning it to a tensor) before accessing its values, or wrap it in a TensorRef.
  7. Avoid using C++ 'auto' with Tensor operations

    main

    Using auto with tensor expressions does not result in a Tensor object; it results in a non-evaluated expression tree. You cannot access individual elements of an auto variable directly because it lacks the () operator required for element access.

    Correct usage: Use auto only when you want to build up a complex expression tree to be evaluated later in a single step. To get actual values, assign the expression to a Tensor, TensorFixedSize, or TensorMap.

    // WRONG: t4 is an expression tree, not a Tensor. This will fail to compile.
    auto t4 = t1 + t2;
    cout << t4(0, 0, 0); 
    
    // CORRECT: Assign to a Tensor to trigger evaluation.
    Tensor<float, 3> t3 = t1 + t2;
    cout << t3(0, 0, 0); // Works
  8. Understand TensorLayout (ColMajor vs RowMajor)

    main

    Eigen Tensors support two memory layouts:

    1. ColMajor (Default): Column-major layout.
    2. RowMajor: Row-major layout.

    Important Constraints:

    • Full Support: Currently, only ColMajor is fully supported. Using RowMajor is not recommended.
    • Type Specification: Layout is part of the type. If not specified, ColMajor is assumed.
    • Compatibility: All operands in an expression must use the same layout. Mixing layouts results in a compilation error.

    Changing Layout

    You can change the layout using the swap_layout() method. Note that swap_layout() also reverses the order of the dimensions. To preserve dimension order while changing layout, use .swap_layout().shuffle(shuffle) with a shuffle array.

    // Explicitly defining layouts
    Tensor<float, 3, ColMajor> col_major; // Default
    TensorMap<Tensor<float, 3, RowMajor>> row_major(data, ...);
    
    // Swapping layout (reverses dimension order)
    Tensor<float, 2, ColMajor> col_major_res = row_major.swap_layout();
    
    // Swapping layout while preserving dimension order
    Eigen::array<int, 2> shuffle(1, 0);
    auto preserved = row_major.swap_layout().shuffle(shuffle);
  9. How to use Eigen unsupported modules

    main

    To use modules located in the unsupported/ directory, you must include them using one of two methods:

    1. Via Include Path: Add the path_to_eigen/unsupported directory to your compiler's include path. You can then include modules using the standard Eigen syntax: #include <Eigen/ModuleHeader>

    2. Direct Path: Include the module by specifying the unsupported prefix directly: #include <unsupported/Eigen/ModuleHeader>

    // Option 1: If path_to_eigen/unsupported is in your include path
    #include <Eigen/ModuleHeader>
    
    // Option 2: Direct inclusion
    #include <unsupported/Eigen/ModuleHeader>