Overall Statistics
Total Trades
1008
Average Win
0.43%
Average Loss
-0.34%
Compounding Annual Return
1.468%
Drawdown
15.400%
Expectancy
0.173
Net Profit
32.579%
Sharpe Ratio
0.263
Probabilistic Sharpe Ratio
0.015%
Loss Rate
48%
Win Rate
52%
Profit-Loss Ratio
1.26
Alpha
0
Beta
0.134
Annual Standard Deviation
0.049
Annual Variance
0.002
Information Ratio
-0.519
Tracking Error
0.155
Treynor Ratio
0.097
Total Fees
$0.00
Estimated Strategy Capacity
$1800000.00
Lowest Capacity Asset
AUDUSD 8G
"""
Useful References:
-QC.Securities Namespace link
https://www.quantconnect.com/lean/documentation/topic26198.html
-QC SecurityExchange Class Members
https://www.quantconnect.com/lean/documentation/topic26905.html
-QC SecurityExchangeHours Class Members
https://www.quantconnect.com/lean/documentation/topic26922.html

-Data Consolidation Example Algo
https://github.com/QuantConnect/Lean/blob/master/Algorithm.Python/DataConsolidationAlgorithm.py
-Link to list of built-in indicators for QC (from Github)
https://github.com/QuantConnect/Lean/tree/master/Indicators
"""
################################################################################
# BACKTEST DETAILS
CASH = 1e6
START_DATE = '05-01-2002' #'05-01-1971' # MM-DD-YYYY format
END_DATE   = None #'12-31-1971' # MM-DD-YYYY format (or None for to date)
TIMEZONE = 'US/Central' # e.g. 'US/Eastern', 'US/Central', 'US/Pacific'

# Lookback period in months for fundamental indices trend scores
TREND_PERIOD = 12
# Turn on/off using the simplified version basing the desired country weights on 
#  blended scores only and not the rankings against the other countries
# When using this logic, it is essentially looking at absolute momentum rather than cross-sectional momentum
SIMPLIFIED_WEIGHTS = False

# Set the currency exchange to use
CURRENCY_EXCHANGE = 'Oanda' # either 'Oanda' or 'FXCM'

# Set the benchmark - must be an equity/etf
BENCHMARK = "SPY"

# Set your quandl authorization code
QUANDL_AUTH_CODE = 'ZYmz4yBbyvxrejZ44hKo'

# DEFINE COUNTRIES TO TRACK
COUNTRIES = [
    'Australia',
    'Canada',
    # 'France',
    # 'Germany',
    # 'Italy',
    'Europe',
    'Japan',
    'UK',
    # 'USA'
    ]
    
# DEFINE THE WEIGHTS FOR PORTFOLIO CONSTRUCTION
WEIGHT_EA = 0.5 # economic activity weight
WEIGHT_IN = 0.5 # inflation weight
    
# DEFINE CURRENCIES TO TRADE
TRADE_CURRENCIES = True # turn on/off using this data
CURRENCIES = {}
CURRENCIES['Australia'] = 'AUDUSD' # QC oanda data starts 2002-05-05, fxcm starts 2007-03-30
CURRENCIES['Canada']    = 'USDCAD' # QC oanda data starts 2002-05-06, fxcm starts 2007-03-30
CURRENCIES['Europe']    = 'EURUSD' # QC oanda data starts 2002-05-05, fxcm starts 2007-03-30
CURRENCIES['Japan']     = 'USDJPY' # QC oanda data starts 2002-05-05, fxcm starts 2007-03-30
CURRENCIES['UK']        = 'GBPUSD' # QC oanda data starts 2002-05-05, fxcm starts 2007-03-30

# Instead trade based on FRED exchange rates
TRADE_FRED_RATES = False # turn on/off using this data
FRED = {}
# Enter FRED rate codes below
FRED['Australia'] = 'DEXUSAL'
FRED['Canada']    = 'DEXCAUS'
FRED['Europe']    = 'DEXUSEU'
FRED['Japan']     = 'DEXJPUS'
FRED['UK']        = 'DEXUSUK'

# Enter CSV download links below
# The countries need to be ALL CAPS for this
FRED_LINKS = {}
FRED_LINKS['AUSTRALIA'] = 'https://docs.google.com/spreadsheets/d/e/2PACX-1vSaLzwcbVI_2PIQwha5IaIPk8oCymJq5fZtAw-VS20mOty-iEY53MANo1GliCos8TaiLr48RoD_WwQ5/pub?gid=367664124&single=true&output=csv'
FRED_LINKS['CANADA']    = 'https://docs.google.com/spreadsheets/d/e/2PACX-1vSaLzwcbVI_2PIQwha5IaIPk8oCymJq5fZtAw-VS20mOty-iEY53MANo1GliCos8TaiLr48RoD_WwQ5/pub?gid=0&single=true&output=csv'
FRED_LINKS['EUROPE']    = 'https://docs.google.com/spreadsheets/d/e/2PACX-1vSaLzwcbVI_2PIQwha5IaIPk8oCymJq5fZtAw-VS20mOty-iEY53MANo1GliCos8TaiLr48RoD_WwQ5/pub?gid=748699328&single=true&output=csv'
FRED_LINKS['JAPAN']     = 'https://docs.google.com/spreadsheets/d/e/2PACX-1vSaLzwcbVI_2PIQwha5IaIPk8oCymJq5fZtAw-VS20mOty-iEY53MANo1GliCos8TaiLr48RoD_WwQ5/pub?gid=1378346043&single=true&output=csv'
FRED_LINKS['UK']        = 'https://docs.google.com/spreadsheets/d/e/2PACX-1vSaLzwcbVI_2PIQwha5IaIPk8oCymJq5fZtAw-VS20mOty-iEY53MANo1GliCos8TaiLr48RoD_WwQ5/pub?gid=1282896252&single=true&output=csv'

# QUANDL DATASET CODES
# Country codes for datasets
CODE = {}
CODE['Australia'] = 'AUS'
CODE['Canada']  = 'CAN'
CODE['Europe']  = 'OECDE'
# CODE['France']  = 'FRA'
# CODE['Germany'] = 'DEU'
# CODE['Italy']   = 'ITA'
CODE['Japan']   = 'JPN'
CODE['UK']      = 'GBR'
# CODE['USA']     = 'USA'

# Monthly Industrial Production
IP = {}
for country in COUNTRIES:
    IP[country] = 'OECD/KEI_PRINTO01_' + CODE[country] + '_ST_M'

# # REF: https://www.quandl.com/data/OECD/KEI_PRINTO01_CAN_ST_M-Industrial-production-s-a-Canada-Level-ratio-or-index-Monthly
# IP['Canada']  = 'OECD/KEI_PRINTO01_CAN_ST_M'
# # REF: https://www.quandl.com/data/OECD/KEI_PRINTO01_FRA_ST_M-Industrial-production-s-a-France-Level-ratio-or-index-Monthly
# IP['France']  = 'OECD/KEI_PRINTO01_FRA_ST_M'
# # REF: https://www.quandl.com/data/OECD/KEI_PRINTO01_DEU_ST_M-Industrial-production-s-a-Germany-Level-ratio-or-index-Monthly
# IP['Germany'] = 'OECD/KEI_PRINTO01_DEU_ST_M'
# # REF: https://www.quandl.com/data/OECD/KEI_PRINTO01_ITA_ST_M-Industrial-production-s-a-Italy-Level-ratio-or-index-Monthly
# IP['Italy']   = 'OECD/KEI_PRINTO01_ITA_ST_M'
# # REF: https://www.quandl.com/data/OECD/KEI_PRINTO01_JPN_ST_M-Industrial-production-s-a-Japan-Level-ratio-or-index-Monthly
# IP['Japan']   = 'OECD/KEI_PRINTO01_JPN_ST_M'
# # REF: https://www.quandl.com/data/OECD/KEI_PRINTO01_GBR_ST_M-Industrial-production-s-a-United-Kingdom-Level-ratio-or-index-Monthly
# IP['UK']      = 'OECD/KEI_PRINTO01_GBR_ST_M'
# # REF: https://www.quandl.com/data/OECD/KEI_PRINTO01_USA_ST_M-Industrial-production-s-a-United-States-Level-ratio-or-index-Monthly
# IP['USA']     = 'OECD/KEI_PRINTO01_USA_ST_M'

# Monthly Retail Sales
RS = {}
for country in COUNTRIES:
    RS[country] = 'OECD/KEI_SLRTTO01_' + CODE[country] + '_ST_M'

# # REF: https://www.quandl.com/data/OECD/KEI_SLRTTO01_CAN_ST_M-Retail-trade-Volume-s-a-Canada-Level-ratio-or-index-Monthly
# RS['Canada'] = 'OECD/KEI_SLRTTO01_CAN_ST_M'
# # REF: https://www.quandl.com/data/OECD/KEI_SLRTTO01_USA_ST_M-Retail-trade-Volume-s-a-United-States-Level-ratio-or-index-Monthly
# RS['USA']    = 'OECD/KEI_SLRTTO01_USA_ST_M'

# Monthly Unemployment
UE = {}
for country in COUNTRIES:
    UE[country] = 'OECD/STLABOUR_' + CODE[country] + '_LFHUTTTT_ST_M'

# # REF: https://www.quandl.com/data/OECD/STLABOUR_CAN_LFHUTTTT_ST_M-Canada-Unemployment-Monthly-Total-All-Persons-Level-Rate-Or-Quantity-Series
# UE['Canada'] = 'OECD/STLABOUR_CAN_LFHUTTTT_ST_M'
# # REF: https://www.quandl.com/data/OECD/STLABOUR_USA_LFHUTTTT_ST_M-United-States-Harmonised-Unemployment-Monthly-Total-All-Persons-Level-Rate-Or-Quantity-Series
# UE['USA']    = 'OECD/STLABOUR_USA_LFHUTTTT_ST_M'

# Monthly Consumer Prices
CP = {}
for country in COUNTRIES:
    CP[country] = 'OECD/KEI_CPALTT01_' + CODE[country] + '_ST_M'

# # REF: https://www.quandl.com/data/OECD/KEI_CPALTT01_CAN_ST_M-Consumer-prices-all-items-Canada-Level-ratio-or-index-Monthly
# CP['Canada'] = 'OECD/KEI_CPALTT01_CAN_ST_M'
# # REF: https://www.quandl.com/data/OECD/KEI_CPALTT01_USA_ST_M-Consumer-prices-all-items-United-States-Level-ratio-or-index-Monthly
# CP['USA']    = 'OECD/KEI_CPALTT01_USA_ST_M'

# Monthly Producer Prices
PP = {}
for country in COUNTRIES:
    PP[country] = 'OECD/KEI_PIEAMP01_' + CODE[country] + '_ST_M'

# # REF: https://www.quandl.com/data/OECD/KEI_PIEAMP01_CAN_ST_M-Producer-prices-Manufacturing-Canada-Level-ratio-or-index-Monthly
# PP['Canada'] = 'OECD/KEI_PIEAMP01_CAN_ST_M'
# # REF: https://www.quandl.com/data/OECD/KEI_PIEAMP01_USA_ST_M-Producer-prices-Manufacturing-United-States-Level-ratio-or-index-Monthly
# PP['USA']    = 'OECD/KEI_PIEAMP01_USA_ST_M'


# Set the number of warmup days
CALENDAR_WARMUP_DAYS = 50

# Turn on/off specific logs
PRINT_WARMUP = False # print logs during warmup for debugging
# PRINT_BARS   = False # print desired OHLC bars for debugging
PRINT_SIGNALS = True # print desired trading signals

################################################################################ 
############################ END OF ALL USER INPUTS ############################
################################################################################

# VALIDATE USER INPUTS - DO NOT CHANGE BELOW

#-------------------------------------------------------------------------------
import datetime as DT
# Verify start date
try:
    START_DATE_DT = DT.datetime.strptime(START_DATE, '%m-%d-%Y')
except:
    raise ValueError("Invalid START_DATE format ({}). Must be in MM-DD-YYYY "
        "format.".format(START_DATE))
        
# Verify end date
try:
    if END_DATE:
        END_DATE_DT = DT.datetime.strptime(END_DATE, '%m-%d-%Y')
except:
    raise ValueError("Invalid END_DATE format ({}). Must be in MM-DD-YYYY "
        "format or set to None to run to date.".format(END_DATE))
        
# Verify CURRENCY_EXCHANGE
if CURRENCY_EXCHANGE not in ['Oanda', 'FXCM']:
    raise ValueError("Invalid CURRENCY_EXCHANGE ({}). Must be 'Oanda' or "
        "'FXCM'.".format(CURRENCY_EXCHANGE))
        
###############################################################################
# Standard library imports
import datetime as DT
# from datetime import timedelta
# from datetime import date
from dateutil.parser import parse
import decimal
import math
# import numpy as np
# import pandas as pd
import pytz

# QuantConnect specific imports
import QuantConnect as qc
from QuantConnect.Python import PythonQuandl

# Import from files
from notes_and_inputs import *

################################################################################
class CustomTradingStrategy(QCAlgorithm):
    def Initialize(self):
        """Initialize algorithm."""
        # Set backtest details
        self.SetStartDate(
            START_DATE_DT.year, START_DATE_DT.month, START_DATE_DT.day)
        if END_DATE:
            self.SetEndDate(
                END_DATE_DT.year, END_DATE_DT.month, END_DATE_DT.day)
        self.SetCash(CASH)
        self.SetTimeZone(TIMEZONE)
        
        # Set your personal token necessary for restricted dataset
        Quandl.SetAuthCode(QUANDL_AUTH_CODE)
        
        # Set up dictionaries to hold all Quandl custom datasets
        self.industrial_production = {}
        self.retail_sales = {}
        self.unemployment = {}
        self.consumer_prices = {}
        self.producer_prices = {}
        self.symbols = {}
        
        # Loop through all desired countries to track
        for country in COUNTRIES:
            # Get all industrial production datasets
            self.industrial_production[country] = self.AddData(
                QuandlCustomColumns, 
                IP[country], 
                Resolution.Daily, 
                TimeZones.NewYork
                ).Symbol
            # Get all retail sales datasets
            self.retail_sales[country] = self.AddData(
                QuandlCustomColumns, 
                RS[country], 
                Resolution.Daily, 
                TimeZones.NewYork
                ).Symbol
            # Get all unemployment datasets
            self.unemployment[country] = self.AddData(
                QuandlCustomColumns, 
                UE[country], 
                Resolution.Daily, 
                TimeZones.NewYork
                ).Symbol
            # Get all consumer prices datasets
            self.consumer_prices[country] = self.AddData(
                QuandlCustomColumns, 
                CP[country], 
                Resolution.Daily, 
                TimeZones.NewYork
                ).Symbol
            # Get all producer prices datasets
            self.producer_prices[country] = self.AddData(
                QuandlCustomColumns, 
                PP[country], 
                Resolution.Daily, 
                TimeZones.NewYork
                ).Symbol
                
            # Add data to trade
            if TRADE_CURRENCIES:
                # Add built-in currency data from the desired exchange
                if CURRENCY_EXCHANGE == 'Oanda': # either 'Oanda' or 'FXCM'
                    exchange = Market.Oanda
                else:
                    exchange = Market.FXCM
                self.symbols[country] = \
                    self.AddForex(CURRENCIES[country], Resolution.Hour, exchange).Symbol
            elif TRADE_FRED_RATES:
                # Add FRED rate data
                self.symbols[country] =\
                    self.AddData(MyCustomData, country, Resolution.Daily).Symbol
                
        # Set benchmark for scheduling purposes
        self.bm = self.AddEquity(BENCHMARK, Resolution.Hour).Symbol
        
        # Rebalance the portfolio at the end of every month at market close
        self.Schedule.On(
            self.DateRules.MonthEnd(self.bm),
            self.TimeRules.BeforeMarketClose(self.bm, 0), 
            self.Rebalance)
            
        # Initialize required variables
        self.portfolio_targets = []
        
        try:
            self.TREND_PERIOD = int(self.GetParameter("TREND_PERIOD"))
        except:
            self.TREND_PERIOD = TREND_PERIOD
            
        # Warm up the indicators prior to the start date
        self.SetWarmUp(timedelta(CALENDAR_WARMUP_DAYS))
        
#-------------------------------------------------------------------------------
    def OnData(self, data):
        """Built-in event handler for new data."""
        # Check for new portfolio targets
        if len(self.portfolio_targets) > 0:
            # Update portfolio
            self.SetHoldings(self.portfolio_targets)
            # Empty portfolio targets list
            self.portfolio_targets = []
            
#-------------------------------------------------------------------------------
    def Rebalance(self):
        """Rebalance the portfolio."""   
        # First calculate the economic momentum scores and get the desired
        #  country weights
        self.CalculateScores()
        
        # Loop through each country and get the portfolio targets for each
        self.portfolio_targets = []
        for country in COUNTRIES:
            # Get the desired country weight
            if country in self.weights:
                target_weight = self.weights[country]
            else:
                target_weight = 0
            
            # Get the instrument to trade for the country
            symbol = self.symbols[country]
            
# # Verify that data is available for the symbol
# if not self.Securities[symbol].HasData:
#     continue
            
            # Check if USD is the base or quote currency
            # 'USD' is the base currency if at beginning of symbol
            usd_base = False
            if TRADE_CURRENCIES and 'USD' == str(symbol)[:3]:
                usd_base = True
            elif TRADE_FRED_RATES:
                # Get the FRED rate code
                fred_code = str(FRED[country])[3:] # remove 'DEX' at beginning
                if 'US' == fred_code[:2]:
                    usd_base = True
            if usd_base:
                # Want to sell to go long the country currency
                # So inverse the target weight
                target_weight = -target_weight
            # else: # 'USD' is the quote currency
            
            # Set the target allocation for the currency
            self.portfolio_targets.append(
                PortfolioTarget(symbol, target_weight)
                )
                
#-------------------------------------------------------------------------------
    def CalculateScores(self):
        """Calculate the economic momentum scores for all countries.""" 
        # Create dictionaries to store country specific index scores
        ea_index = {} # economic activity index
        in_index = {} # inflation index
        weight = {} # overall desired weight for each country
        
        # Loop through each country
        for country in COUNTRIES:
            # Get history for all 5 of the fundamental factors
            length = (TREND_PERIOD+1+6)*31 # get an extra 5-6 months of data
            hist_ip = self.History([self.industrial_production[country]], length)
            hist_rs = self.History([self.retail_sales[country]], length)
            hist_ue = self.History([self.unemployment[country]], length)
            hist_cp = self.History([self.consumer_prices[country]], length)
            hist_pp = self.History([self.producer_prices[country]], length)
            
# we can test different lookback periods in QC's optimization feature, but it takes some extra compute power (discuss with Jon later - need to just get it working for now)
            # Get the economic activity index
            if min([len(hist_ip), len(hist_rs), len(hist_ue)]) > TREND_PERIOD+1:
                # Get the industrial production log growth rate
                ip = math.log(hist_ip.iloc[-1].value) \
                    -math.log(hist_ip.iloc[-TREND_PERIOD-1].value)
                # Get the retail sales log growth rate
                rs = math.log(hist_rs.iloc[-1].value) \
                    -math.log(hist_rs.iloc[-TREND_PERIOD-1].value)
                # Get the unemployment log growth rate
                ue = math.log(hist_ue.iloc[-1].value) \
                    -math.log(hist_ue.iloc[-TREND_PERIOD-1].value)
                # Calculate the economic activity index
                # equal weighted average of factors above
                ea_index[country] = (ip+rs+ue)/3.0
            else:
                ea_index[country] = 0
                
            # Get the inflation index
            if min([len(hist_cp), len(hist_pp)]) > TREND_PERIOD+1:
                # Get the consumer prices log growth rate
                cp = math.log(hist_cp.iloc[-1].value) \
                    -math.log(hist_cp.iloc[-TREND_PERIOD-1].value)
                pp = math.log(hist_pp.iloc[-1].value) \
                    -math.log(hist_pp.iloc[-TREND_PERIOD-1].value)
                # Calculate the inflation index
                # equal weighted average of factors above
                in_index[country] = (cp+pp)/2.0
            else:
                in_index[country] = 0
                
        # Check if SIMPLIFIED_WEIGHTS is used
        if SIMPLIFIED_WEIGHTS:
            # Loop through each country
            for country in COUNTRIES:
                # Get the overall desired weight based on raw blended score
                blended_score = WEIGHT_EA*ea_index[country] + WEIGHT_IN*in_index[country]
                if blended_score > 0:
                    weight[country] = 1
                elif blended_score < 0:
                    weight[country] = -1
                else:
                    weight[country] = 0
        else:   
            # Now get rankings for each index
            # reverse=True for those we want to sort in descending order
            sorted_ea = sorted(ea_index.items(), key=lambda x: x[1], reverse=True)
            sorted_in = sorted(in_index.items(), key=lambda x: x[1], reverse=True)
            
            ea_ranks = list(range(1,len(sorted_ea)+1))
            ea_avg_rank = sum(ea_ranks)/len(ea_ranks)
            in_ranks = list(range(1,len(sorted_in)+1))
            in_avg_rank = sum(in_ranks)/len(in_ranks)
            
            # Loop through each country
            for country in COUNTRIES:
# paper mentions a 3month lag on using this data for the portfolio
                # Get the economic activity score
                if country in ea_index:
                    rank_ea = [x[0] for x in sorted_ea].index(country)+1
                    inverse_rank_ea = ea_ranks[-rank_ea]
# this formula doesn't make sense to me - discuss with Jon
                    score_ea = inverse_rank_ea - ea_avg_rank # sum([x[0] for x in sorted_ea])/len(sorted_ea)
                else:
                    score_ea = 0
                # Get the inflation score
                if country in in_index:
                    rank_in = [x[0] for x in sorted_in].index(country)+1
                    inverse_rank_in = in_ranks[-rank_in]
# this formula doesn't make sense to me - discuss with Jon
                    score_in = inverse_rank_in - in_avg_rank # sum([x[0] for x in sorted_in])/len(sorted_in)
                else:
                    score_in = 0
                # Get the overall desired weight
                weight[country] = WEIGHT_EA*score_ea + WEIGHT_IN*score_in
                
        # NOTE: weight adds up to 0 / longs + shorts
        # Make sure absolute values of long and short weights add to 1
        if sum([abs(x[1]) for x in weight.items()]) != 1:
            # Rescale so absolute value of long weights and short weights add to 1
            weights_sum = sum([abs(x[1]) for x in weight.items()])
            if weights_sum > 0:
                factor = 1.0/weights_sum
            else:
                factor = 0
            for country in COUNTRIES:
                weight[country] = factor*weight[country]
            
        # Save weights and return
        self.weights = weight
        
        return
    
#-------------------------------------------------------------------------------
    def CustomSecurityInitializer(self, security):
        """
        Define models to be used for securities as they are added to the 
        algorithm's universe.
        """
        # Define the data normalization mode
        security.SetDataNormalizationMode(DataNormalizationMode.Adjusted)
        
        # Define the fee model to use for the security
        # security.SetFeeModel()
        # Define the slippage model to use for the security
        # security.SetSlippageModel()
        # Define the fill model to use for the security
        # security.SetFillModel()
        # Define the buying power model to use for the security
        # security.SetBuyingPowerModel()
        
################################################################################
class QuandlCustomColumns(PythonQuandl):
    """
    Quandl often doesn't use close columns so need to tell LEAN which is the 
    "value" column.
    REF: https://www.quantconnect.com/forum/discussion/11566/kei-based-strategy/p1
    """
    def __init__(self):
        # Define ValueColumnName: cannot be None, Empty or non-existant column name
        self.ValueColumnName = "Value"
        
################################################################################
class MyCustomData(PythonData):
    """
    Custom Data Class
    REF: https://www.quantconnect.com/forum/discussion/4079/python-best-practise-for-using-consolidator-on-custom-data/p1
    """
    def GetSource(self, config, date, isLiveMode):
        # Get file specific to the asset symbol
        country = config.Symbol.Value
        # Get the custom url link for the FRED data for the desired country
        file = FRED_LINKS[country]
        return SubscriptionDataSource(
            file, SubscriptionTransportMedium.RemoteFile)

    def Reader(self, config, line, date, isLiveMode):
        # Create new object
        asset = MyCustomData()
        asset.Symbol = config.Symbol
        
        # If first character is not a digit, return
        if not (line.strip() and line[0].isdigit()):
            return None
            
        # try:
        # Example File Format:
        # Date                      Price  
        # 2017-01-02 09:02:00+01:00 64.88
        
        # Comma separated file, so split data row by comma
        data = line.split(',')
        
        # If price is invalid, return None
        try:
            value = float(data[1])
        except:
            return None
        # Return None if value is 0
        if value == 0:
            return None
            
        # Set time of data at close 16:00 / 57600s = 16hr*60min/hr*60s/min
        # Set time of data at close 16:01 / 57660s = 16hr*60min/hr*60s/min
        # asset.Time = parse(data[0]) #+ timedelta(seconds=57660)
        asset.Time = DT.datetime.strptime(data[0], "%m/%d/%Y")
        
        # Set the value used for filling positions
        asset.Value = value #decimal.Decimal(data[1])
        asset["Close"] = value
        
        return asset
            
        # except ValueError:
        #     # Do nothing
        #     return None