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>
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:
- Highcharts library inclusion
- Responsive container styling
- 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
- Colors: Modify color properties in series configurations
- Labels: Adjust date formatting in formatPeriods()
- Styling: Modify plotOptions for columns/splines
- 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
- Blank Chart
- Verify container element ID matches
- Check browser console for errors
- Ensure API URLs are accessible (CORS issues)
- Incorrect Data Display
- Verify data formatting in console logs
- Check timestamp conversions
- Ensure all series have valid data points
- 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>
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