CHF corporate bonds

There is (or was) an annual CS review of Swiss issuers that I’d like to get my hands on if I can. I’ve asked my guy there if he can source the most recent edition.
With regards the credit risk, Im going to diversify that somewhat with an equivalent amount in longer term bond funds (corporate and gvmt) which is extremely diversified or extremely safe. Should have no more than 1% exposure to single issuer other than Swiss Confederation.

Im thinking of moving my FZK to FinPension and using something like UBS AST Obligationen CHF Indexiert I-X institutional fund.
That would be completely tax shielded, but I need to do the maths, as it might make more sense to put equity funds in the FZK to shield the dividend yield.

The nearest ETF is something like UBS ETF (CH) SBI ESG AAA-BBB (CHF) A-dis
which has a TER 0.15% and an ICTax yield of 1.2% and a YTM 1.9% so a net return of 1.9%-(1.2x20%)-0.15%=1.5%, compared to FinP 2.0%-0.5%=1.5%… maybe better to use FZK for equity funds. I think the yield difference is due to the preferential WHT regime for the FZK Stiftung.

Although ICTax taxable income is also in the region of 1.8% for global equity funds, your best tax bang for the buck would probably be to put Swiss large cap exposure there, since SMI dividend yield is about 2.6%… the tax savings would cover the FinPens fees. In practise I think I’ll just replicate the overall portfolio exposure in the FZK.

1 Like

I got annoyed by the poor tooling for Swiss bonds (YTM calculation seems to be inconsistent, some take the last traded price which is pretty useless when liquidity is low, others take the mid price which can also be useless when the spread is high, for others it is not clear at all how they arrive at their YTM number), so I wrote a small Python script that parses the current SIX order books and calculates the YTM’s at the current ask prices, i.e. the prices that you can currently trade instantly. Here is an example with Pfandbriefe, but you can just replace the URL with your own filters (go to the SIX screener, set the filters, copy the URL under “Download”). Might be helpful for others:

import csv
import requests
from io import StringIO

url = ',ISIN,ClosingPrice,CouponRate,IssuerNameShort,ValorSymbol,ValorNumber,YieldToWorst,DurationToWorst,SubscriptionPaymentDueDate,RemainingTermOfMaturity,MaturityDate,AmountInIssue,ProductLineDesc,TradingBaseCurrency,ClosingPerformance,ClosingDelta,BidVolume,BidPrice,AskPrice,AskVolume,MidSpread,PreviousClosingPrice,LatestTradeDate,LatestTradeTime,OpeningPrice,DailyHighPrice,DailyLowPrice,OnMarketVolume,OffBookVolume,TotalTurnover,TotalTurnoverCHF,GeographicalAreaDesc,IndustrySectorDesc,SecTypeDesc,BondListedFlag,BondDutyToReportFlag,SpecialFlagDesc&where=PortalSegment=BO*IssuerNameFull_~Pfandbriefzentrale\\20der\\20schweizerischen\\20Kantonalbanken&orderby=ShortName&page=1&pagesize=99999'
response = requests.get(url)
csv_data = response.content.decode("utf-8")

csv_reader = csv.DictReader(StringIO(csv_data), delimiter=';')

def calculate_ytm(coupon_rate, remaining_term, ask_price):
    coupon_rate /= 100

    ytm = ((coupon_rate * 100) + ((100 - ask_price) / remaining_term)) / ((100 + ask_price) / 2) * 100

    return ytm

filtered_bonds = []
csv_reader = csv.DictReader(StringIO(csv_data), delimiter=';')

bonds = list(csv_reader)

for bond in bonds:
    if bond['CouponRate'] == "":
        coupon_rate = 0
        coupon_rate = float(bond['CouponRate'])
    if bond['RemainingTermOfMaturity'] == "":
    remaining_term = float(bond['RemainingTermOfMaturity'])
    if bond['AskPrice'] == "-Market":
    ask_price = float(bond['AskPrice'])

    ytm = calculate_ytm(coupon_rate, remaining_term, ask_price)
    bond['YTM'] = ytm

sorted_bonds = sorted(filtered_bonds, key=lambda x: float(x['RemainingTermOfMaturity']))

for bond in sorted_bonds:
    print(f"ISIN: {bond['ISIN']}, Remaining Term of Maturity: {bond['RemainingTermOfMaturity']}, YTM: {bond['YTM']}")

Thanks @0xLambda for your script.

I had three problems with your script:

  1. In my case the csv was not utf-8 encoded and I got an UnicodeDecodeError
    Fix: mine csv was iso-8859-1 encoded
  2. When I had a big list I got the error field larger than field limit (131072)
    Easy fixed with increasing the limit csv.field_size_limit(sys.maxsize)
  3. Sometimes the AskPrice was an empty string
    Fix: if bond['AskPrice'] == "-Market" or bond['AskPrice'] == '':

Maybe this will help someone who has less Python knowledge and has the same problems.

Too late now but did you consider getting USD bonds (spoilt for choice there) and then hedging the currency risk?

You may earn less than investing in CH bonds. Most of the times in the last years the CCY basis favored CHF investments, ie if you invested in USD and hedged by an FX forward, you earned less than investing in CHF bonds (assuming comparable credit quality of the underlying bond)…

Yes, the idea of using USD instruments is that he would have been able stick with IBKR and not have the hassle and expense of opening a new account with Swissquote.

Considered it, but as far as I know, you cannot completely hedge FX risks as a retail investor on IBKR. You would need duration-matched forward contracts, but I think you can only buy CME futures that you need to rollover constantly. As I am already quite exposed to currency risk (because 70-80% of my earnings are in USD), I would like to eliminate it for the fixed income part of my portfolio completely.

Also not sure what the margin requirements on IBKR for CME futures are, but I guess you will not be able to use a bond with face value $100,000 as collateral for a $100,000 future and would need additional collateral.

I hope someone can help me understand this topic. I am trying to compare the following options to buy bond ETFs (Swiss corporate) . Both track the same index.

CHCORP (ishares ETF)
CS Corporate Blue (Index Fund) CH0281860343

The TER for both of these are similar. However CHCORP trades at premium to its NAV of about 0.3-0.4%. On the other hand, the CS Bond fund has a buy-in spread of 0.35%

So how it looks like, the buy-in price for both of these instruments is same with respect to the NAV. But I would expect that ETF premium would remain constant and hence it’s not really an extra cost. Am I right? And thus it would make CS fund more expensive to buy?

In terms of performance, it seems CS performs better than ishares in term of tracking its index. In fact the performance is much better (not sure why though)

In the end all this might be small differences in terms of costs. But just wanted to understand if a ETF trading at premium is better or worse than a buy-in spread for a fund.

An ETF premium may stay or may not. Probably it will.
A buy-in spread, if you buy directly, not via VIAC/finpension, is lost definitely.

I don’t think they count your initial fee into the performance, therefore it is purely NAV development. I also don’t know how my comment is related to your question :joy:.

1 Like

Not sure if someone has mentioned it, but there is also

Furthermore, this ETF is the closest thing to an aggregated bond ETF in CHF that I have found:

As a relative “newbie” to Kassenobligationen (I chose Cembra), I’d like to learn a bit about these bonds, so if you’ve bought bonds would appreciate “more details” :slight_smile:

So, as an example, I found this bond CEMBRA CV 19-26, ISIN: CH0486598227 Symbol: CMB19 which currently trades at 95.70 CHF
expires in July 2026, 0% interest.

  1. I buy today for 95.7 and get 100 in July 2026, correct? So approx 2% p.a.
  2. Tax-free, as it’s a capital gain?
  3. Do I buy at any Swiss broker? And usual fees like for stocks, say at Swissquote, Fr 100 for 25k? Is this trading fee also charged when it expires, or is that “free”?
  4. Does the “smallest tradable amount” of the bond of 200k not apply (in the bond details, when found via your link)?
  5. In the bond details it shows an “average spread” of 0.58%. Is this realistic? So for the price shown of 95.7, I would expect to pay 95.7+0.6= CHF 96.3? Or 95.7 + 0.5*0.6 = CHF 96? If held to expiry in July 2026 no spread i.e. 100?
  6. If you can’t comment on Swissquote fees, which broker did you use, and what were typical costs incurred?

Comparable Kassenobligation (Cembra, 2y) would be 1.6% less tax on this income = 1.2%.
Fees = 0

Zero coupon bonds are taxed.

The main difference between mid term notes issued by and deposited at a Swiss bank and corporate bonds of the same bank for a private investor is that mid term notes are protected by esuisuisse up to 100k CHF per bank relationship. So this basically boosts the effective credit rating of that debt from typical Bsomething to AAA.

This is exactly the situation where the return of your investment is more important than the return on your investment. As I see it, as a private investor, you don’t diversify by buying debts of hundreds of issuers. You want to park your money while making reasonable precautions that they will be still there later.


Thank you @oslasho for your (as always) precise answers.
I now recall reading this thread we are in now ( where some of my questions would’ve already been answered), but my question-post was originally added to a different thread, so I missed the “reminder”.

esisuisse protected 25k Kassenobligation from Cembra, after tax (at my income tax rate) and fees = return 1.2% p.a.

Top corp. bonds (so for the same / similar risk) ~1.2% to ETF 1.6% minus 0.4% fee for purchase and some spread and possibly Verwahrung-fee = return say ~1% to 1.3% p.a. (assuming no tax).

I’ll stick to the Kassenobligationen from Cembra.

PS I rounded the Fr 80 commission to Fr 100 to include VAT, stamp fee etc. :slight_smile:

1 Like

0.4% fees to buy bond ETF seems high.
CHCORP is quite cheap to buy on IBKR
And CS BLUE corp bond fund is available at flat 9 CHF


agreed-chose a bond with a coupon of 0.XX% with XX ideally being as close to zero but not zero.