#### Important:

User must create the above two functions

The platform at AimsQuant is divided into two main sections, strategy editor (or the "editor") section and community section. In this tutorial, we will discuss the editor section of the platform. The editor section of the platform is divided into three major components

- Code Editor
- Settings Panel
- Toolbar

In code editor, user can define backtest settings and write strategy logic. Every strategy is subdivided into two function:

`initialize()`

: Used to define settings like universe, dates, commission model etc.`ondata()`

: Used to write strategy logic. This function is called every time stamp and re-evaluates the strategy logic

User must create the above two functions

```
#Initialize function to set basic strategy parameters
function initialize(state)
setcash(100000.0)
setstartdate("2016-01-01")
setenddate("2017-10-01")
.
setcancelpolicy("EOD")
.
.
setcommission(("PerTrade", 0.02))
end
#Strategy logic
function ondata(data, state)
price_history = dropnan(history(["TCS","WIPRO"], "Close", :Day, 22))
log_returns = percentchange(price_history, :log)
ts_end = timestamp(log_returns)[end]
names = colnames(log_returns)
vals_end = reshape(cumsum(values(log_returns), dims=1)[end, :], (1,length(names)))
#Convert to timeseries
total_return = TimeSeries.TimeArray([ts_end], vals_end, names)
if values(total_return["TCS"])[1] > values(total_return["WIPRO"])[1]
setholdingpct("WIPRO", 0.0)
setholdingpct("TCS", 1.0)
else
setholdingpct("TCS", 0.0)
setholdingpct("WIPRO", 1.0)
end
end
```

User can also create sub-functions to break-down strategy logic into easy to comprehend sections. For ex: the function that calculates returns based on price data can be taken out of the ondata() function.

```
#Strategy logic
#Strategy logic
function ondata(data, state)
price_history = dropnan(history(["TCS","WIPRO"], "Close", :Day, 22))
totalreturn = calculate_totalreturn(price_history)
if values(total_return["TCS"])[1] > values(total_return["WIPRO"])[1]
setholdingpct("WIPRO", 0.0)
setholdingpct("TCS", 1.0)
else
setholdingpct("TCS", 0.0)
setholdingpct("WIPRO", 1.0)
end
end
#Calculate total returns
function calculate_totalreturn(price_history)
log_returns = percentchange(price_history, :log)
ts_end = timestamp(log_returns)[end]
names = colnames(log_returns)
vals_end = reshape(cumsum(values(log_returns), dims=1)[end, :], (1,length(names)))
#Convert to timeseries
total_return = TimeSeries.TimeArray([ts_end], vals_end, names)
end
```

To simplify the `initialize()`

function and to avoid writing basic settings every time, user can use settings panel to set the backtest settings. Settings are divided into Basic and Advanced settings. Initial Cash, backtesting dates, universe selection can be done

All the backtest settings are listed in an easy to understand UI

User can create any combination of settings without writing any code in `initialize()`

`initialize()`

must always be defined. However, it can be left empty

```
function initialize(state)
end
```

settings defined in `initialize()`

WILL override the settings selected in settings panel

In addition to starting a backtest, Toolbar is used to create new strategies, cloning existing strategy, saving a strategy and inspecting previously run backtests for a strategy.

Strategy is saved every 5 seconds to avoid loss of work

In this tutorial, we will create a sample strategy to test the platform, understand the flow of data and available functions in API. In this strategy, 100% of wealth is equally divided and invested in two stocks, TCS and WIPRO.

As mentioned in **Tutorial #1**, we need to
define two functions for successful execution
of a strategy/backtest.

*In the section below, we show the components of strategy/backtest initialization*

```
#Set initial cash
setcash(1000000.0)
```

```
#Set commission (no commission)
setcommission(Commission(PerTrade, 0.0))
```

```
#Set slippage (no slippage)
setslippage(Slippage(Variable, 0.0))
```

```
#Set universe (mandatory before placing any orders)
setuniverse(["TCS", "WIPRO"])
```

*in this section, we define the components of strategy logic*

```
#Get Universe
universe = getuniverse()
```

```
#Set the holding in all stock in universe to 1/total number of stocks [uniform portfolio]
for stock in universe
#Function is executed every Day/Week/Month based on rebalance frequency
setholdingpct(stock, 1.0/length(universe))
end
```

```
#Track the portfolio value
track("Portfoliovalue", state.account.netvalue)
end
```

```
#User Logger to output information to console
Logger.info("Portofolio value = $(state.account.netvalue)")
end
```

Here is the complete strategy

```
#Sample strategy to invest 100% of wealth equally in two stocks
#Every strategy requires two mandatory functions
#1. initialize(): Function to initialize the settings and user defined parameters
#2. ondata(): Function to define strategy logic
#Initialize the strategy with various settings and/or parameters
function initialize(state)
#Set initial cash
setcash(1000000.0)
#Set commission (no commission)
setcommission(Commission(PerTrade, 0.0))
#Set slippage (no slippage)
setslippage(Slippage(Variable, 0.0))
#Set universe (mandatory before placing any orders)
setuniverse(["TCS", "WIPRO"])
end
#Define strategy logic here
#This function is called every DAY
function ondata(data, state)
#Get Universe
universe = getuniverse()
#Set the holding in all stock in universe to 1/total number of stocks [uniform portfolio]
for stock in universe
#Function is executed every Day/Week/Month based on rebalance frequency
setholdingpct(stock, 1.0/length(universe))
end
#Track the portfolio value
track("Portfoliovalue", state.account.netvalue)
#User Logger to output information to console
Logger.info("Portofolio value = $(state.account.netvalue)")
end
```

This is a sample strategy (only to be used for experiment and research purpose). It does NOT constitute an investment advice.

In this strategy, we create a proxy for underperformance by calculating the 22 day returns of stocks. Subsequently, returns are sorted and 100% of wealth is uniformly distributed in least performing 5 stocks.

This strategy is applied only on NIFTY constituents as of 25/01/2017. Hence, it has some shortcomings like sample ** bias** and

`initialize()`

, we set universe as NIFTY constituents
```
##################
# Basic stock reversal strategy
# Rebalances portfolio every week
# Invest in bottom (least performing) 5 stocks of NIFTY based on
# last 22 days return
##################
# Initialize the strategy with various settings and/or parameters
function initialize(state)
# NIFTY 50 stock universe as of 25/01/2017
# This universe has Survivorship bias
universe = ["ACC","ADANIPORTS","AMBUJACEM",
"ASIANPAINT","AUROPHARMA","AXISBANK","BAJAJ_AUTO",
"BANKBARODA","BHEL","BPCL", "BHARTIARTL","INFRATEL",
"BOSCHLTD","CIPLA","COALINDIA","DRREDDY","EICHERMOT",
"GAIL","GRASIM","HCLTECH","HDFCBANK","HEROMOTOCO","HINDALCO",
"HINDUNILVR","HDFC","ITC","ICICIBANK","IDEA",
"INDUSINDBK","INFY","KOTAKBANK","LT","LUPIN","M_M",
"MARUTI","NTPC","ONGC","POWERGRID","RELIANCE","SBIN",
"SUNPHARMA","TCS","TATAMTRDVR","TATAMOTORS","TATAPOWER",
"TATASTEEL","TECHM","ULTRACEMCO","WIPRO","YESBANK","ZEEL"]
# Set universe (mandatory before placing any orders)
# Dynamic universe is not allowed yet
setuniverse(universe)
end
```

In `ondata()`

```
# Get Universe
universe = getuniverse()
# Fetch prices for last 22 days
prices = history(universe, "Close", :Day, 22)
```

```
# Logic to calculate returns over last month
log_returns = percentchange(price_history, :log)
total_return = cumsum(values(log_returns), dims=1)[end, :]
```

```
# Create vector with two columns (Name and Returns)
rets = [String.(colnames(prices_history)) vec(total_returns)]
```

```
# Sorted returns
sortedrets = sortslices(rets, dims=1, by=x->(x[2]))
# Get 5 names with lowest returns
topnames = sortedrets[1:5, 1]
```

```
# Liquidate from portfolio if not in bottom 5 anymore
for (stock, positions) in state.account.portfolio.positions
if (stock.ticker in topnames)
continue
else
setholdingpct(stock, 0.0)
end
end
# Create momemtum portfolio
for (i,stock) in enumerate(topnames)
setholdingpct(stock, 1.0/length(topnames))
end
```

```
##################
# Basic stock reversal strategy
# Rebalances portfolio every week
# Invest in bottom (least performing) 5 stocks of NIFTY based on
# last 22 days return
##################
# Initialize the strategy with various settings and/or parameters
function initialize(state)
# NIFTY 50 stock universe as of 25/01/2017
# This universe has Survivorship bias
universe = ["ACC","ADANIPORTS","AMBUJACEM",
"ASIANPAINT","AUROPHARMA","AXISBANK","BAJAJ_AUTO",
"BANKBARODA","BHEL","BPCL", "BHARTIARTL","INFRATEL",
"BOSCHLTD","CIPLA","COALINDIA","DRREDDY","EICHERMOT",
"GAIL","GRASIM","HCLTECH","HDFCBANK","HEROMOTOCO","HINDALCO",
"HINDUNILVR","HDFC","ITC","ICICIBANK","IDEA",
"INDUSINDBK","INFY","KOTAKBANK","LT","LUPIN","M_M",
"MARUTI","NTPC","ONGC","POWERGRID","RELIANCE","SBIN",
"SUNPHARMA","TCS","TATAMTRDVR","TATAMOTORS","TATAPOWER",
"TATASTEEL","TECHM","ULTRACEMCO","WIPRO","YESBANK","ZEEL"]
# Set universe (mandatory before placing any orders)
# Dynamic universe is not allowed yet
setuniverse(universe)
end
# Define strategy logic: Calculate 22 days return, sort
# and invest 20% of wealth in bottom 5 stocks
# All order based functions are called
# every DAY/WEEK/MONTH (depends on rebalance frequency)
# Default rebalance Frequency: Daily
function ondata(data, state)
# Get Universe
universe = getuniverse()
# Fetch prices for last 22 days
prices = history(universe, "Close", :Day, 22)
# Logic to calculate returns over last month
log_returns = percentchange(price_history, :log)
total_return = cumsum(values(log_returns), dims=1)[end, :]
# Create vector with two columns (Name and Returns)
rets = [String.(colnames(prices)) vec(total_return)]
# Sorted returns
sortedrets = sortslices(rets, dims=1, by=x->(x[2]))
# Get 5 names with lowest retursn
topnames = sortedrets[1:5, 1]
# Liquidate from portfolio if not in bottom 5 anymore
for (stock, positions) in state.account.portfolio.positions
if (stock.ticker in topnames)
continue
else
setholdingpct(stock, 0.0)
end
end
# Create momemtum portfolio
for (i,stock) in enumerate(topnames)
setholdingpct(stock, 1.0/length(topnames))
end
# Track the portfolio value
track("Portfolio Value", state.account.netvalue)
# Output information to console
Logger.info("Portofolio value = $(state.account.netvalue)")
end
```

This is a sample strategy (only to be used for experiment and research purpose). It does NOT constitute an investment advice.

**Utility API** exposes some of the commonly used metrics like price_returns, standard deviation and beta. The API is a wrapper around verbose calculations.

In this tutorial, we will recreate the reversal strategy in **Tutorial #3**.

**
In the reversal strategy, we created a proxy of poor performance by calculating total returns (log returns) over 22 days.
**

```
universe = getuniverse()
#Fetch prices for last 22 days
prices = history(universe, "Close", :Day, 22)
#Logic to calculate returns over last month
log_returns = percentchange(price_history, :log)
ts_end = timestamp(log_returns)[end]
names = colnames(log_returns)
vals_end = reshape(cumsum(values(log_returns), dims=1)[end, :], (1,length(names)))
#Convert to timeseries
total_return = TimeSeries.TimeArray([ts_end], vals_end, names)
```

```
universe = getuniverse()
#Fetch total returns over last 22 days
total_return = UtilityAPI.price_returns(universe, "Close", :Day, window=22, total=true)
```

```
#Also, there are other options to change the return type (log or simple returns) and duration(daily or total)
#To get, daily simple returns
daily_return = UtilityAPI.price_returns(universe, "Close", :Day, window=22, total=false, rettype=:simple)
```

```
#Beta of all stocks in universe over a period of 252 days using
#"log" returns of "Close" price with "benchamrk" as NIFTY 50
bta = UtilityAPI.beta(universe, :Day, window=252, series="Close", benchmark="NIFTY_50", rettype=:log)
#Standard Deviation of all stocks in universe over a period of 22 days using
#"log" returns
std = UtilityAPI.stddev(universe, "Close", :Day, window=22, returns=true, rettype=:log)
#For standard deviation of Open PRICES (not returns), set "returns" as FALSE
std = UtilityAPI.stddev(universe, "Open", :Day, window=22, returns=false)
```

**Optimization API** exposes some of the commonly used optimization methods used in investment management. The API is a wrapper around verbose functions. It uses Julia JuMP library and Ipopt as an optimization engine.

In this tutorial, we will detail the available optimization types and various configuration parameters.

- Minimum absolute deviation
- Minimum semi-absolute deviation
- Mean-Variance
- Minimum volatility
- Minimum Loss
- Minimum Norm

```
#Common API function
#Parameters are employed as required by the optimization type
#Default optimization type is minvol
function optimize(symbols,
method::String="minvol",
window::Int=22;
targeret::Float64=0.2,
nfactors::Int=10,
constraints::Constraints=Constraints(),
initialportfolio::Vector=Vector(),
linearrestrictions::Vector=LinearRestriction[])
end
```

To employ common financial constraints like exposure, leverage, trade-limit, turnover etc., API exposes the type Constraints. Also, to add linear restrictions, API exposes the type LinearRestrictions. Please visit the API to learn more about the functionality.

Here we will discuss the a few use cases of the optimization API.

In minimum volatility, we solve for a portfolio with least standard deviation or variance of portfolio returns. There is no restriction on portfolio return but it can be added via LinearRestriction API. Below we will show a use case which employs both LinearRestriction and Constraints API

In the following minimum volatility optimization, we impose a restriction on position size such that each position is less than 10% of the total portfolio. In addition, we impose a single period turnover limit of 15%. This minimum volatility optimization employs Factor Analysis to decompose stock returns covariance into low dimensional factor covariance. It is mainly a mathematical technique to simplify the problem. We will discuss

```
#Strategy Logic
function ondata(data, state)
universe= getuniverse()
#Compute initial portfolio
init_port=ones(length(universe))/length(universe)
#Get Net Asset Value
nav = getportfoliovalue()
for (i,position) in getallpositions()
init_port[i] = position.lastprice`*`position.quantity/nav
end
#Solve the optimization problem (method = "minvol")
#Add constraint for turnover (<= 15%)
#Add constraint on position limit (Max position size <= 10% of Portfolio)
#nfactors is the number of factors to be used from Factor analysis (Num. Factors = 15)
(obj, opt_port, status) = OptimizeAPI.optimize(universe,
window=66,
method="minvol",
nfactors=15,
constraints=Constraints(maxturnover=0.15, maxpositionlimit=0.1),
initialportfolio=init_port)
if status == :Optimal
#Set the target Portfolio as the optimized portfolio
settargetportfolio(opt_port)
end
end
```

In minimum norm, we solve for least euclidean distance of target portfolio from initial portfolio subject to certain restrictions.

In the following minimum norm optimization, we impose a restriction portfolio beta such that portfolio beta is between 0.95 and 1.0. In addition, we impose a portfolio leverage condition such that portfolio leverage is between 0.95 and 1.05. This minimum volatility optimization employs Factor Analysis to decompose stock returns covariance into low dimensional factor covariance. It is mainly a mathematical technique to simplify the problem. We will detail Factor Analysis in a some other tutorial.

```
#Strategy Logic
function ondata(data, state)
universe= getuniverse()
#Compute initial portfolio
init_port=ones(length(universe))/length(universe)
#Get Net Asset Value
nav = getportfoliovalue()
for (i,position) in getallpositions()
init_port[i] = position.lastprice * position.quantity/nav
end
#Compute stock beta using UtilityAPI
bta = UtilityAPI.beta(universe, :Day, window=252)
#Reshapae beta to 1-d array
bta_arr = reshape(values(bta), (length(universe),))
#66-day Historical returns (as proxy for forward returns)
price_ret = UtilityAPI.price_returns(universe, "Close", :Day, window=66, total=true)
ret_arr = reshape(values(price_ret), (length(universe),))
#Solve the optimization problem (method = "minvol")
#Add constraint on Portfolio Leverage (0.95 <= Portfolio Leverage <= 1.05)
#Add constraint on Portfolio Beta (0.95 <= Portfolio Beta <= 1.0)
#Add constraint on Portfolio Returns (Portfolio Returns >= 0.05)
l_restrictions = [LinearRestriction(bta_arr, 0.95, 1.0), LinearRestriction(ret_arr, 0.05, Inf)]
(obj, opt_port, status) = OptimizeAPI.optimize(universe,
method="minnorm",
constraints=Constraints(minleverage=0.95, maxleverage=1.05),
initialportfolio=init_port,
linearrestrictions=l_restrictions)
if status == :Optimal
setttargetportfolio(opt_port)
end
end
```

Optimization API is in beta and still evolving. Please report any issues on the community.

*
"What is a 'Mean-Variance Analysis'
*

*
A mean-variance analysis is the process of weighing risk (variance) against expected return.
By looking at the expected return and variance of an asset,
investors attempt to make more efficient investment choices – seeking the lowest variance
for a given expected return or seeking the highest expected return
for a given variance level." -
*Investopedia

In Mean-Variance Optimization means, we try to create portfolio that have the maximum mean (expected return) for a given variance of return (or standard deviation of returns) or the minimum variance of return for a given mean (expected return).

Mathematically, this problem can be represented as a

where

- is a vector of portfolio weights
- Ω is the covariance matrix for the returns on the assets in the portfolio
- R is a vector of expected returns.
- w'Ωw is the variance of portfolio return.
- R'w is the expected return on the portfolio.
- μ is the target return of the portfolio

```
function ondata(data, state)
universe = getuniverse()
#Use optimization API to solve mean-variance problem (method = meanvar)
#More parameters include constraints, initialportfolio and linearrestrictions [Tutorial #5]
#Output: Tuple of objective value, optimal portfolio and status of optimization
(obj, optimal_portfolio, status) = OptimizeAPI.optimize(universe, window=66, method="meanvar", targetret=0.2)
if(status == :Optimal)
#Rebalance the portfolio with settargetportfolio (Uses setholdingpct internally)
settargetportfolio(optimal_portfolio)
end
end
```

In other variant of Mean-Variance Optimization, we try to create portfolio by solving the following:

where

- is a vector of portfolio weights
- Ω is the covariance matrix for the returns on the assets in the portfolio
- R is a vector of expected returns.
- w'Ωw is the variance of portfolio return.
- R'w is the expected return on the portfolio.
- λ is risk aversion parameter

```
function ondata(data, state)
universe = getuniverse()
#Use optimization API to solve mean-variance problem (method = "meanvar2")
#Output: Tuple of objective value, optimal portfolio and status of optimization
(obj, opt_port, status) = OptimizeAPI.optimize(universe, window=66, method="meanvar2", targetret=0.2, lamda=1.0)
if(status == :Optimal)
#Rebalance the portfolio with settargetportfolio (Uses setholdingpct internally)
settargetportfolio(opt_port)
end
end
```

This is a sample strategy (only for experiment and research purpose) and DOES NOT constitute an investment advice