Overall Statistics
Total Trades
63
Average Win
30.80%
Average Loss
-9.28%
Compounding Annual Return
59.860%
Drawdown
61.000%
Expectancy
0.881
Net Profit
2299.967%
Sharpe Ratio
1.518
Probabilistic Sharpe Ratio
91.282%
Loss Rate
56%
Win Rate
44%
Profit-Loss Ratio
3.32
Alpha
0.522
Beta
-0.011
Annual Standard Deviation
0.343
Annual Variance
0.118
Information Ratio
1.059
Tracking Error
0.367
Treynor Ratio
-46.456
Total Fees
$3264.13
# https://quantpedia.com/strategies/time-series-momentum-combined-with-volatility-filters-in-futures-markets/
#
# The investment universe consists of stocks of firms whose fleet consists of tankers more than 66% (DHT Holding, Teekay, Tsakos 
# Energy Nav and Capital Product Partners). Nextly, consider a variable BT(t) that is the natural logarithm of the Baltic Tanker 
# Index at time t and two moving averages are employed: a six-week (long-term) moving average MA(6) and the lag of the relationship
# (short-term) denoted as MA(1). When the short-term moving average exceeds the long-term moving average, it is considered as a buy
# signal, because it suggests that prices are moving higher at a faster rate than in the past. On the other hand, when the short-term
# moving average passes below the long-term moving average, it is considered as a sell signal. In-between the crossovers, strategy 
# dictates that investor continues to be in the market (for example after a buy signal the algorithm buys and holds until a sell signal is found).

import fk_tools
import numpy as np
from collections import deque

class Using_Baltic_Dry_Index_Tanker_Shipping_Companies(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2013, 1, 1)
        self.SetEndDate(2019, 10, 1)
        self.SetCash(100000)
        
        self.symbol = 'BADI'
        
        data = self.AddData(QuantpediaEquity, self.symbol, Resolution.Daily)
        data.SetFeeModel(fk_tools.CustomFeeModel(self))
        
        self.period = 6*5
        self.SetWarmUp(self.period)
        
        self.sma_6 = self.SMA(self.symbol, self.period, Resolution.Daily)
        self.sma_1 = self.SMA(self.symbol, 5, Resolution.Daily)
        
    def OnData(self, data):
        if self.IsWarmingUp: return

        if self.sma_1.Current.Value > self.sma_6.Current.Value:
            if not self.Portfolio[self.symbol].IsLong:
                self.SetHoldings(self.symbol, 1)
        else:
            if not self.Portfolio[self.symbol].IsShort:
                self.SetHoldings(self.symbol, -1)
                    
# NOTE: IMPORTANT: Data order must be ascending (datewise)
class QuantpediaEquity(PythonData):
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("data.quantpedia.com/backtesting_data/equity/{0}.csv".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)

    def Reader(self, config, line, date, isLiveMode):
        data = QuantpediaEquity()
        data.Symbol = config.Symbol
        
        if not line[0].isdigit(): return None
        split = line.split(';')
        
        data.Time = datetime.strptime(split[0], "%m/%d/%Y")
        data['settle'] = float(split[1])
        data.Value = float(split[1])

        return data
import numpy as np
from collections import deque

def Return(values):
    return (values[-1] - values[0]) / values[0]
    
def Volatility(values):
    values = np.array(values)
    returns = (values[1:] - values[:-1]) / values[:-1]
    return np.std(returns)  

# Custom fee model
class CustomFeeModel(FeeModel):
    def GetOrderFee(self, parameters):
        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005
        return OrderFee(CashAmount(fee, "USD"))
        
# Quantpedia data
# NOTE: IMPORTANT: Data order must be ascending (datewise)
class QuantpediaFutures(PythonData):
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("data.quantpedia.com/backtesting_data/futures/{0}.csv".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)

    def Reader(self, config, line, date, isLiveMode):
        data = QuantpediaFutures()
        data.Symbol = config.Symbol
        
        if not line[0].isdigit(): return None
        split = line.split(';')
        
        data.Time = datetime.strptime(split[0], "%d.%m.%Y") + timedelta(days=1)
        data['settle'] = float(split[1])
        data.Value = float(split[1])

        return data