Examples of use

Below we provide some examples of how our API can be used. Please note our terms of use, especially:

  • You are responsible for licensing any software you use.
  • We do not provide any additional support for your own implementation of our API endpoints.

This PHP based example fetches the fund profile API endpoint by cURL and places all parts in a HTML structure.

<?php

// Get cURL resource
$curl = curl_init();

// Set some options - we are passing in a useragent too here
curl_setopt_array($curl, [
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_URL            => 'https://fondsapi.hansainvest.com/api/fund/DE0008479023/profile',
    CURLOPT_USERAGENT      => 'Sample cURL Request',
    CURLOPT_HTTPHEADER     => [
        'Accept: application/json',
        'Accept-Language: en',
    ],
]);

// Send the request & save response to $respJson
$respJson    = curl_exec($curl);
$fundProfile = json_decode($respJson);

// Close request to clear up some resources
curl_close($curl);

// All the data is provided in the array variable $fundProfile
// You can see the complete structure e.g. by using var_dump()
// var_dump($fundProfile); 
?>

<h3 class="hi-profile-name"><?php echo $fundProfile->name; ?></h3>
<h4 class="hi-profile-isin">ISIN: <?php echo $fundProfile->isin; ?> /
    WKN: <?php echo $fundProfile->wkn; ?></h4>
<p><small>Status: <?php echo date(
            'd.m.Y',
            strtotime($fundProfile->status_date)
        ); ?></small></p>
<table class="table hi-profile">
    <tbody>
    <tr>
        <th scope="row">Fund category</th>
        <td class="hi-profile-fund_category"><?php echo $fundProfile->category; ?></td>
    </tr>
    <tr>
        <th scope="row">Inception date</th>
        <td class="hi-profile-fund_inception_date"><?php echo date(
                'd.m.Y',
                strtotime($fundProfile->fund_inception_date)
            ); ?></td>
    </tr>
    <tr>
        <th scope="row">Currency</th>
        <td class="hi-profile-currency"><?php echo $fundProfile->currency; ?></td>
    </tr>
    <tr>
        <th scope="row">Fund assets</th>
        <td class="hi-profile-fund_assets"><?php echo $fundProfile->fund_assets; ?></td>
    </tr>
    <tr>
        <th scope="row">Total fund assets</th>
        <td class="hi-profile-total_fund_assets"><?php echo $fundProfile->total_fund_assets; ?></td>
    </tr>
    <tr>
        <th scope="row">End of fiscal year</th>
        <td class="hi-profile-end_of_fiscal_year"><?php echo $fundProfile->end_of_fiscal_year; ?></td>
    </tr>
    <tr>
        <th scope="row">Dividend distribution</th>
        <td class="hi-profile-dividend_distributions"><?php echo $fundProfile->dividend_distributions; ?></td>
    </tr>
    <tr>
        <th scope="row">Conformity</th>
        <td class="hi-profile-conformity"><?php echo $fundProfile->conformity ? 'yes' : 'no'; ?></td>
    </tr>
    <tr>
        <th scope="row">Issue surcharge</th>
        <td class="hi-profile-issue_surcharge"><?php echo $fundProfile->issue_surcharge; ?></td>
    </tr>
    <tr>
        <th scope="row">Redemption fee</th>
        <td class="hi-profile-redemption_fee"><?php echo $fundProfile->redemption_fee; ?></td>
    </tr>
    <tr>
        <th scope="row">TER (total expense ratio)</th>
        <td class="hi-profile-total_expense_ratio"><?php echo $fundProfile->total_expense_ratio; ?> % p.a.</td>
    </tr>
    <tr>
        <th scope="row"> incl. management fee</th>
        <td class="hi-profile-management_fee"><?php echo $fundProfile->management_fee; ?> % p.a.</td>
    </tr>
    <tr>
        <th scope="row"> incl. custodian bank fee</th>
        <td class="hi-profile-custodian_bank_fee"><?php echo $fundProfile->custodian_bank_fee; ?> % p.a.</td>
    </tr>
    <tr>
        <th scope="row">Performance fee</th>
        <td class="hi-profile-performance_fee"><?php echo $fundProfile->performance_fee ? 'yes' : 'no'; ?></td>
    </tr>
    <?php foreach ($fundProfile->possible_investments as $investment): ?>
        <tr>
            <th scope="row"><?php echo $investment->name; ?></th>
            <td class="hi-profile-investment">
                <?php
                if ($investment->possible) {
                    echo 'yes';

                    if ($investment->minimum_investment) {
                        echo sprintf(
                            ' (%s %s)',
                            $investment->minimum_investment,
                            $investment->currency
                        );
                    }
                } else {
                    echo 'no';
                }
                ?>
            </td>
        </tr>
    <?php endforeach; ?>
    <tr>
        <th scope="row">Countries</th>
        <td class="hi-profile-countries"><?php echo implode(', ', $fundProfile->countries); ?></td>
    </tr>
    <tr>
        <th scope="row">Cut-off time</th>
        <td class="hi-profile-cut-off-time"><?php echo $fundProfile->cut_off_time; ?></td>
    </tr>
    <tr>
        <th scope="row">Minimum equity participation</th>
        <td class="hi-profile-minimum-equity-participation"><?php echo $fundProfile->minimum_equity_participation; ?>%</td>
    </tr>
    <tr>
        <th scope="row">Cut-off time</th>
        <td class="hi-profile-cut-off-time"><?php echo $fundProfile->cut_off_time; ?></td>
    </tr>
    <tr>
        <th scope="row">Active management</th>
        <td class="hi-profile-active-management"><?php echo ($fundProfile->management_aktiv ?? false) ? 'yes'
                : 'no'; ?></td>
    </tr>
    <?php if ($fundProfile->sri_risk): ?>
        <tr>
            <th scope="row">SRI risk</th>
            <td class="hi-profile-sri-risk"><?php echo $fundProfile->sri_risk; ?></td>
        </tr>
        <tr>
            <th scope="row">SFDR article</th>
            <td class="hi-profile-sri-risk"><?php echo $fundProfile->sfdr_article; ?></td>
        </tr>
    <?php endif; ?>
    </tbody>
</table>
<a class="hi-profile-link" href="<?php echo $fundProfile->url; ?>">all fund details</a>

Preview

This example implementation is based on our 2 API endpoints PerformancePeriods and PerformanceDays and features a chart based on Highcharts that combines the data of the endpoints.

Basic Setup

HTML Structure

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="UTF-8">
    <title>Highcharts demo</title>

    <!-- Highcharts Library -->
    <script src="https://code.highcharts.com/highcharts.js"></script>
    
    <!-- Chart Container Styles -->
    <style>
        #container { height: 400px; }
        .chart {
            min-width: 310px;
            max-width: 800px;
            margin: 1em auto;
        }
    </style>
</head>
<body>
    <figure class="chart">
        <div id="chart-container"></div>
    </figure>
</body>
</html>

Key elements:

  1. Highcharts library inclusion
  2. Responsive container styling
  3. Chart placeholder div (chart-container)

Data Fetching

API Endpoints used

// URL to the PerformancePeriods endpoint for a fund
const urlPeriods = 'https://fondsapi.hansainvest.com/api/fund/DE0008479098/performance-periods';

/** 
 * URL to the PerformanceDays endpoint for a fund, 
 * the starting date will be added later
 */
const urlDays    = 'https://fondsapi.hansainvest.com/api/fund/DE0008479023/performance-days?start=';
        

Fetching Data

/**
 * Fetch the PerformanceDays endpoint asynchronously (Javascript Fetch API) and return data as JSON
 */
const dataPeriods = await fetch(
    urlPeriods
).then(response => response.json());

// formatted periods data
const chartPeriodsData = formatPeriods(dataPeriods.performance);

/**
 * Fetch the PerformanceDays endpoint asynchronously (Javascript Fetch API) regarding the starting date got 
 * from the PerformancePeriods endpoint and return data as JSON
 */

const dataDays = await fetch(
    urlDays + chartPeriodsData.start
).then(response => response.json());

Data Formatting

The data from the endpoints does not match the formatting that is needed for the Highcharts implementation.

Formatting data from the PerformancePeriods endpoint

/**
 * Takes the JSON data of the PerformancePeriods endpoint and formats it to fit the Highcharts
 * requirements
 * 
 * @param periodsData
 * @returns {{start: null, periods: *[], gross: *[], net: *[]}}
 */
function formatPeriods (periodsData) {
    let returnObject = {
        start: null, // starting date for the chart
        periods: [], // periods formatted for the x axis legend
        gross: [],   // gross performance data for the periods
        net: []      // net performance data for the periods
    };
    for (const periodsDataItem of periodsData) {
        if (!returnObject.start) {
            returnObject.start = periodsDataItem.realfrom ?? periodsDataItem.from;
        }

        returnObject.gross.push(periodsDataItem.gross);
        returnObject.net.push(periodsDataItem.gross);
        returnObject.periods.push(new Date(periodsDataItem.from).toLocaleDateString() + ' - ' + new Date(periodsDataItem.to).toLocaleDateString());
    }
    
    return returnObject;
}

Formatting data from the PerformanceDays endpoint

const daysData   = [];

/**
 * Formatting the daily performance data in a way Highcharts understands
 */
for (const datePerformance of dataDays.performance) {
    if (!startTimestamp) {
        startTimestamp = Date.parse(datePerformance.date);
    }
    daysData.push([Date.parse(datePerformance.date), datePerformance.value - 100]);
}

Chart Configuration

Basic Chart Setup

new Highcharts.Chart("chart-container", {
    title: { text: null },
    legend: { /*...*/ },
    credits: { enabled: false }
});

Axis Configuration

yAxis: {
    gridLineDashStyle: "Dot",
    tickAmount: 8
},
xAxis: [{
    type: "category",        // For period columns
    categories: periodLabels
},{
    type: "datetime",        // For daily spline
    visible: false
}]

Series Configuration

series: [
    // Gross Performance Columns
    {
        name: "gross",
        type: "column",
        data: chartPeriodsData.gross,
        color: "#BADA55"
    },
    
    // Net Performance Columns
    {
        name: "net",
        type: "column",
        data: chartPeriodsData.net,
        color: "#C55"
    },
    
    // Daily Performance Line
    {
        name: "cumulative (gross)",
        type: "spline",
        data: daysData,
        color: "#336699",
        xAxis: 1  // Uses second xAxis
    }
]

Customization Guide

Common Customizations

  1. Colors: Modify color properties in series configurations
  2. Labels: Adjust date formatting in formatPeriods()
  3. Styling: Modify plotOptions for columns/splines
  4. Tooltips: Update tooltip.pointFormat

Style Customization Example

plotOptions: {
    column: {
        dataLabels: {
            enabled: true,
            format: "{point.y:.1f}%"
        }
    },
    spline: {
        lineWidth: 2,
        marker: { enabled: false }
    }
}

Troubleshooting

Common Issues

  1. Blank Chart
    • Verify container element ID matches
    • Check browser console for errors
    • Ensure API URLs are accessible (CORS issues)
  2. Incorrect Data Display
    • Verify data formatting in console logs
    • Check timestamp conversions
    • Ensure all series have valid data points
  3. Styling Issues
    • Verify CSS units and selectors
    • Check Highcharts configuration options
    • Ensure color codes are valid

Debugging Tips

// Add console logs to inspect data
console.log('Period Data:', dataPeriods);
console.log('Daily Data:', dataDays);

Next steps

Using the following complete example HTML/JS code as a basis

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Highcharts demo</title>

    <script src="https://code.highcharts.com/highcharts.js"></script>
    <style>
        #container {
            height: 400px;
        }

        .chart {
            min-width: 310px;
            max-width: 800px;
            margin: 1em auto;
        }
    </style>
</head>
<body>
    <figure class="chart">
        <div id="chart-container"></div>
    </figure>


    <script>
        
        // URL to the PerformancePeriods endpoint for a fund
        const urlPeriods = 'https://fondsapi.hansainvest.com/api/fund/DE0008479098/performance-periods';

        /** 
         * URL to the PerformanceDays endpoint for a fund, 
         * the starting date will be added later
         */
        const urlDays    = 'https://fondsapi.hansainvest.com/api/fund/DE0008479023/performance-days?start=';
        
        // starting UNIX timestamp for the Highcharts chart
        let startTimestamp = 0;

/**
 * Takes the JSON data of the PerformancePeriods endpoint and formats it to fit the Highcharts
 * requirements
 * 
 * @param periodsData
 * @returns {{start: null, periods: *[], gross: *[], net: *[]}}
 */
function formatPeriods (periodsData) {
    let returnObject = {
        start: null, // starting date for the chart
        periods: [], // periods formatted for the x axis legend
        gross: [],   // gross performance data for the periods
        net: []      // net performance data for the periods
    };
    for (const periodsDataItem of periodsData) {
        if (!returnObject.start) {
            returnObject.start = periodsDataItem.realfrom ?? periodsDataItem.from;
        }

        returnObject.gross.push(periodsDataItem.gross);
        returnObject.net.push(periodsDataItem.gross);
        returnObject.periods.push(new Date(periodsDataItem.from).toLocaleDateString() + ' - ' + new Date(periodsDataItem.to).toLocaleDateString());
    }
    
    return returnObject;
}

        (async () => {
            
            /**
             * Fetch the PerformanceDays endpoint asynchronously (Javascript Fetch API) and return data as JSON
             */
            const dataPeriods = await fetch(
                urlPeriods
            ).then(response => response.json());

            // formatted periods data
            const chartPeriodsData = formatPeriods(dataPeriods.performance);

            /**
             * Fetch the PerformanceDays endpoint asynchronously (Javascript Fetch API) regarding the starting date got 
             * from the PerformancePeriods endpoint and return data as JSON
             */
            
            const dataDays = await fetch(
                urlDays + chartPeriodsData.start
            ).then(response => response.json());

const daysData   = [];

/**
 * Formatting the daily performance data in a way Highcharts understands
 */
for (const datePerformance of dataDays.performance) {
    if (!startTimestamp) {
        startTimestamp = Date.parse(datePerformance.date);
    }
    daysData.push([Date.parse(datePerformance.date), datePerformance.value - 100]);
}

            /**
             * Generate the Highcharts chart
             * 
             * It is a combined chart:
             *  - spline chart for the daily data
             *  - column chart for the periods data (gross and net values)
             *  
             */
            new Highcharts.Chart("chart-container", {
                title: {
                    text: null
                },
                legend: {
                    enabled: true, 
                    layout: "horizontal", 
                    verticalAlign: "bottom", 
                    useHTML: true
                },
                yAxis: {
                    title: {
                        enabled: false
                    },
                    gridLineDashStyle: "Dot",
                    gridLineColor: "#666666", // change to your own needs
                    tickAmount: 8,
                    startOnTick: false,
                    endOnTick: false,
                    minPadding: 0.2,
                    maxPadding: 0.2
                },
                xAxis: [
                    {
                        type: "category",
                        categories: chartPeriodsData.periods,
                        gridLineDashStyle: "Dot",
                        gridLineWidth: 1,
                        gridLineColor: "#666666", // change to your own needs
                        labels : {
                            autoRotation: [-50, -60, -70, -80, -90]
                        }
                    },
                    {
                        type: "datetime", 
                        visible: false, 
                        min: startTimestamp // important configuration because the first daily performance may not be on 
                                            // the same day as the first period's starting date
                    }
                ],
                labels: {
                    style: {
                        fontSize: "13px"
                    }
                },
                credits: {
                    enabled: false
                },
                plotOptions: {
                    column: {
                        dataLabels: {
                            enabled: true,
                            useHTML: true,
                            format: "{point.y:.1f}",
                            crop: false,
                            overflow: "none",
                            backgroundColor: "",
                            zIndex: 10
                        }, 
                        softThreshold: false
                    },
                    spline: {
                        lineWidth: 1,
                        marker: {
                            enabled: false
                        },
                        dataLabels: {
                            format: "{point.y:.1f}"
                        }
                    }
                },
                tooltip: {
                    changeDecimals: 2,
                    valueDecimals: 1,
                    pointFormat: "<span style=\"color:{series.color}\">{series.name}<\/span>: <b>{point.y} %<\/b><br\/>"
                },
                series: [{
                    name: "gross",
                    data: chartPeriodsData.gross,
                    type: "column",
                    color: "#BADA55" // change to your own needs
                }, {
                    name: "net",
                    data: chartPeriodsData.net,
                    type: "column",
                    color: "#C55" // change to your own needs
                }, {
                    name: "cumulative\u0020\u0028gross\u0029",
                    data: daysData,
                    type: "spline",
                    color: "#336699", // change to your own needs
                    xAxis: 1
                }]
            });
        })();
        
    </script>
</body>
</html>

Preview

Customizing the chart

If you want to use a Highcharts based chart, feel free to get more information on https://www.highcharts.com

  • Demos
  • Documentation
  • Licensing information/costs

Alternively there a many other charting libraries for your implementation.

This PHP based example fetches fund price data from the Prices endpoint and stores it in a MySQL database.

<?php
/**
 * Fund Price Importer
 *
 * Fetches fund price data from a REST API and stores it in a MySQL database
 * Uses PDO for database operations and cURL for API requests
 */

// ==============================================
// Database Configuration
// ==============================================
$dbHost = 'localhost';      // Database server hostname
$dbName = 'fund_prices_db'; // Name of the target database
$dbUser = 'your_username';  // Database username
$dbPass = 'your_password';  // Database password
$isin   = 'DE0008479023';     // ISIN of the fund to track

try {
    // ==============================================
    // Database Connection Setup
    // ==============================================
    $pdo = new PDO(
        "mysql:host=$dbHost;dbname=$dbName;charset=utf8mb4", $dbUser, $dbPass, [
            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, // Throw exceptions on errors
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // Return associative arrays
            PDO::ATTR_EMULATE_PREPARES   => false, // Use native prepared statements
        ]
    );

    // ==============================================
    // Table Creation
    // ==============================================
    $createTableQuery = "
    CREATE TABLE IF NOT EXISTS fund_prices (
        id INT(11) AUTO_INCREMENT PRIMARY KEY,
        isin VARCHAR(12) NOT NULL,
        price_date DATE NOT NULL,
        issue_price DECIMAL(10,3) NOT NULL,
        repurchase_price DECIMAL(10,3) NOT NULL,
        change_percent DECIMAL(5,3) NOT NULL,
        performance_percent DECIMAL(5,2) NOT NULL,
        net_asset_value DECIMAL(10,3) NOT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        UNIQUE KEY unique_price (isin, price_date)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    ";

    // Execute table creation query
    $pdo->exec($createTableQuery);

    // ==============================================
    // API Request Configuration
    // ==============================================
    $apiUrl = "https://fondsapi.hansainvest.com/api/fund/$isin/prices";

    // Configure cURL request
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $apiUrl);          // Set API endpoint URL
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);  // Return response as string
    curl_setopt($ch, CURLOPT_FAILONERROR, true);     // Fail on HTTP 400+ status
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);  // Enable SSL certificate verification
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);           // 10-second timeout

    // Execute API request
    $response = curl_exec($ch);

    // Handle cURL errors
    if (curl_errno($ch)) {
        throw new Exception('API request failed: ' . curl_error($ch));
    }

    // Verify HTTP status code
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    if ($httpCode !== 200) {
        throw new Exception("API returned unexpected status code: $httpCode");
    }

    curl_close($ch);

    // ==============================================
    // Response Processing
    // ==============================================
    $data = json_decode($response, true);

    // Validate response structure
    if (!isset($data['prices']) || !is_array($data['prices'])) {
        throw new Exception('Invalid API response - missing or malformed prices array');
    }

    // ==============================================
    // Database Insert Preparation
    // ==============================================
    $stmt = $pdo->prepare(
        "
        INSERT INTO fund_prices (
            isin, 
            price_date, 
            issue_price, 
            repurchase_price, 
            change_percent, 
            performance_percent, 
            net_asset_value
        ) VALUES (
            :isin, 
            :price_date, 
            :issue_price, 
            :repurchase_price, 
            :change_percent, 
            :performance_percent, 
            :net_asset_value
        )
        ON DUPLICATE KEY UPDATE
            issue_price = VALUES(issue_price),
            repurchase_price = VALUES(repurchase_price),
            change_percent = VALUES(change_percent),
            performance_percent = VALUES(performance_percent),
            net_asset_value = VALUES(net_asset_value)
    "
    );

    // ==============================================
    // Data Processing & Transaction Management
    // ==============================================
    $pdo->beginTransaction();
    $processedCount = 0;

    foreach ($data['prices'] as $index => $entry) {
        // Validate required fields exist in the response
        $requiredFields = [
            'date',
            'issue_price',
            'repurchase_price',
            'change',
            'performance',
            'net_asset_value',
        ];

        foreach ($requiredFields as $field) {
            if (!isset($entry[$field])) {
                error_log("Skipping entry $index - missing field: $field");
                continue 2; // Continue outer loop (skip this entry)
            }
        }

        // Validate and parse date format
        $date = DateTime::createFromFormat('Y-m-d', $entry['date']);
        if (!$date) {
            error_log("Skipping entry $index - invalid date format: {$entry['date']}");
            continue;
        }

        // Prepare parameters with type casting
        $params = [
            ':isin'                => $isin,
            ':price_date'          => $date->format('Y-m-d'),
            ':issue_price'         => (float)$entry['issue_price'],
            ':repurchase_price'    => (float)$entry['repurchase_price'],
            ':change_percent'      => (float)$entry['change'],
            ':performance_percent' => (float)$entry['performance'],
            ':net_asset_value'     => (float)$entry['net_asset_value'],
        ];

        // Execute insert/update operation
        try {
            $stmt->execute($params);
            $processedCount++;
        } catch (PDOException $e) {
            error_log("Error processing entry $index: " . $e->getMessage());
            continue; // Skip failed entry but continue processing others
        }
    }

    // Commit transaction if all operations succeeded
    $pdo->commit();

    // ==============================================
    // Output Results
    // ==============================================
    echo "Successfully processed $processedCount price entries\n";
    echo "Skipped " . (count($data['prices']) - $processedCount) . " invalid/malformed entries\n";
} catch (PDOException $e) {
    // Rollback transaction on database errors
    if (isset($pdo) && $pdo->inTransaction()) {
        $pdo->rollBack();
    }
    echo "Database Error: " . $e->getMessage();
    exit(1); // Return non-zero exit code
} catch (Exception $e) {
    // Rollback transaction on application errors
    if (isset($pdo) && $pdo->inTransaction()) {
        $pdo->rollBack();
    }
    echo "Application Error: " . $e->getMessage();
    exit(1); // Return non-zero exit code
} finally {
    // ==============================================
    // Cleanup Resources
    // ==============================================
    $pdo = null; // Close database connection
}

Usage Notes:

  • The script should be run periodically (e.g. via cron job)
  • Monitor error logs for skipped entries
  • Database credentials should be stored securely in production
  • Adjust decimal precision in table creation as needed