Overall Statistics
Total Orders
255
Average Win
5.28%
Average Loss
-3.21%
Compounding Annual Return
0.676%
Drawdown
60.500%
Expectancy
0.092
Start Equity
100000
End Equity
113135.85
Net Profit
13.136%
Sharpe Ratio
0.02
Sortino Ratio
0.025
Probabilistic Sharpe Ratio
0.000%
Loss Rate
59%
Win Rate
41%
Profit-Loss Ratio
1.65
Alpha
0.032
Beta
-0.46
Annual Standard Deviation
0.195
Annual Variance
0.038
Information Ratio
-0.197
Tracking Error
0.295
Treynor Ratio
-0.008
Total Fees
$0.00
Estimated Strategy Capacity
$970000.00
Lowest Capacity Asset
USDJPY 8G
Portfolio Turnover
3.25%
#region imports
from AlgorithmImports import *
#endregion
# https://quantpedia.com/Screener/Details/8
# Create an investment universe consisting of several currencies (15). 
# Go long 3 currencies with strongest 12 month momentum against USD and 
# go short 3 currencies with lowest 12 month momentum against USD.


class FXMomentumAlgorithm(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2006, 1, 1) 
        self.set_cash(100000) 
        # create a dictionary to store momentum indicators for all symbols 
        self._data = {}
        period = 12*21
        # choose 15 forex pairs
        symbols = ["USDAUD", "USDCAD", "USDCHF", "USDEUR", "USDGBP", 
                   "USDHKD", "USDJPY", "USDDKK", "USDCZK", "USDZAR",
                   "USDSEK", "USDSAR", "USDNOK", "USDMXN", "USDHUF"]
                        
        # warm up the MOM indicator
        self.set_warm_up(period)
        for symbol in symbols:
            self.add_forex(symbol, Resolution.DAILY, Market.OANDA)
            self._data[symbol] = self.mom(symbol, period, Resolution.DAILY)
        # shcedule the function to fire at the month start 
        self.schedule.on(self.date_rules.month_start("USDEUR"), self.time_rules.after_market_open("USDEUR"), self._rebalance)

    def _rebalance(self):
        if self.is_warming_up: 
            return
        top3 = pd.Series(self._data).sort_values(ascending=False)[:3]
        for symbol, security_hold in self.portfolio.items():
            # liquidate the security which is no longer in the top3 momentum list
            if security_hold.invested and (symbol.value not in top3.index):
                self.liquidate(symbol)
        
        added_symbols = []
        for symbol in top3.index:
            if not self.portfolio[symbol].invested:
                added_symbols.append(symbol)
        for added in added_symbols:
            self.set_holdings(added, 1/len(added_symbols))