% Kozak, Nagel, and Santosh (2019): ``Shrinking the Cross 
% Section'', Journal of Financial Economics.
%
% Copyright 2019, Serhiy Kozak, Stefan Nagel, and Shri Santosh. 
%
% First Version: 2017-04-20. Serhiy Kozak.
% This  Version: 2019-08-08. Serhiy Kozak.

% Modified: 2021-11-08. Jiaen Li. 

addpath('.\KNS 2020');

clear; clear global; clc; close all;
tic


%% options 
daily = false; % use daily return (this option is provided in KNS(2020), for our purpose, always set daily=false as we use monthly data only)
if daily
    display('Using daily data');
else
    display('Estimating SCS SDF using the monthly data.');
end

% number of managed portfolios
G = 70; 

% include L1 penalty or not
L1pen = true;

% fixed L1 penalty models
fixedL1pen = [2,4,5];% each element corresponds to a fixed L1 model, 
                       % the value is the number of factors with non-zero SDF loadings.

% rotate returns into PC space 
rotate_PC = true;

% choose the basis/test assets 
dataprovider = 'anom';

% sample dates
t0 = datenum('01-Jan-1974');
tN = datenum('31-Dec-2016');
oos_test_date = '01DEC2003'; % the last date of training sample, t>oos_test_date is the test sample

% current run
% run_folder = [upper(datestr(today, 'ddmmmyy')) '/'];

% daily file suffix
if daily
    freq = 252;
    suffix = '_d';
    date_fmt = 'mm/dd/yyyy';
else
    freq = 12;
    suffix = '';
    date_fmt = 'mm/yyyy';
end
       
%% paths
projpath = './KNS 2020/';
datapath = [projpath 'Data/'];
instrpath = [datapath 'instruments/'];

% Fix random number generation
rng default;

%% default estimation parameters
default_params = struct( ...
    'gridsize', 20, ... % size of the grid
    'contour_levelstep', 0.01, ... % L1L2 contour map plot: level step of contour lines 
    'L1pen', L1pen, ... % choose to add L1 penalty or not
    'fixedL1pen', fixedL1pen,... % fixed L1 models, if p.L1pen = false, this parameter is not used
    'objective', 'CSR2', ... % objective used in the paper
    'rotate_PC', rotate_PC, ... % pre-rotate assets into the PC space
    'demarket_unconditionally', true,... % should always set to be true 
    'devol_unconditionally', false, ... % should be true unless constant-leveraged (already scaled) portfolios are used
    'kfold', 3, ... % 3-fold cross-validation
    'plot_dof', false, ... % show plots
    'plot_coefpaths', true, ...
    'plot_L1L2countour',false,...
    'plot_objective', false);
default_params.fig_options.fig_sizes = {'width=half'}; 
% default_params.fig_options.fig_sizes = {'width=full', 'width=half'}; % produce pictures in two sizes
default_params.fig_options.close_after_print = true; % close figure after saving

% load FF factors and save for future use ("ALWAYS RUN THIS PIECE OF CODE" @Serhiy Kozak)
% re = ['SMB', 'HML', 'Mom', 'RMW' ,'CMA']
[dd, re, ~] = load_ff_anomalies(datapath, daily, t0, tN);
global ff_factors ff_factors_dates; ff_factors = re; ff_factors_dates = dd;


% parameters
p = default_params;

p.gridsize = 100;



%% estimate SDF

% find the appropriate file by mask
fmask = [instrpath 'managed_portfolios_' dataprovider suffix '_' num2str(G) '.csv'];
flist = ls(fmask); 
assert(~isempty(flist), 'No such managed portfolios data file found. Check fmask.');

filename = [instrpath strip(flist(1,:))]; %assert(length(filename)>length(instrpath), ['File not found: ' fmask]);
display('Use the following input data to estimated SDF:');
display(filename);


% parameters
p.L1_truncPath = true; 


% load data
[dd, re, mkt, anomalies] = load_managed_portfolios(filename, daily, 1, 0.2); 

dd_index = find(dd>=t0 & dd<=tN);
dd=dd(dd_index); re=re(dd_index,:);mkt=mkt(dd_index);

% In-sample estimate
p_is = SCS_L1L2est(dd, re, mkt, freq, anomalies, p);


%% Output: 
%in-sample SDF (MVE portfolios)
 
if p.demarket_unconditionally % if demarketed the managed portfolios,
                          % need to include the market factor when
                          % measuring the pricing performance.

    output_is = [dd, p_is.optimal_model_fixedL1.MVE_IS, p_is.optimal_model_L1L2.MVE_IS, mkt];

else
    output = [dd, p.optimal_model_fixedL1.MVE_IS, p.optimal_model_L1L2.MVE_IS];
end
    
   

save('SCS_IS.mat', 'output_is'); 


















