// Main Part 1 about a really dumb investment strategy
//=====================================================
// generate jar with
// > scala -d drumb.jar drumb.scala
object M1 {
//two test portfolios
val blchip_portfolio = List("GOOG", "AAPL", "MSFT", "IBM", "FB", "AMZN", "BIDU")
val rstate_portfolio = List("PLD", "PSA", "AMT", "AIV", "AVB", "BXP", "CCI",
"DLR", "EQIX", "EQR", "ESS", "EXR", "FRT", "HCP")
import io.Source
import scala.util._
// (1) The function below takes a stock symbol and a year as arguments.
// It should read the corresponding CSV-file and reads the January
// data from the given year. The data should be collected in a list of
// strings for each line in the CSV-file.
def get_january_data(symbol: String, year: Int) : List[String] =
Source.fromFile(symbol ++ ".csv")("ISO-8859-1").getLines().toList.filter(_.startsWith(year.toString))
//test cases
//blchip_portfolio.map(get_january_data(_, 2018))
//rstate_portfolio.map(get_january_data(_, 2018))
//get_january_data("GOOG", 1980)
//get_january_data("GOOG", 2010)
//get_january_data("FB", 2014)
//get_january_data("PLD", 1980)
//get_january_data("EQIX", 2010)
//get_january_data("ESS", 2014)
// (2) From the output of the get_january_data function, the next function
// should extract the first line (if it exists) and the corresponding
// first trading price in that year with type Option[Double]. If no line
// is generated by get_january_data then the result is None; Some if
// there is a price.
def get_first_price(symbol: String, year: Int) : Option[Double] = {
val data = Try(Some(get_january_data(symbol, year).head)) getOrElse None
data.map(_.split(",").toList(1).toDouble)
}
//test cases
//get_first_price("GOOG", 1980)
//get_first_price("GOOG", 2010)
//get_first_price("FB", 2014)
/*
for (i <- 1978 to 2018) {
println(blchip_portfolio.map(get_first_price(_, i)))
}
for (i <- 1978 to 2018) {
println(rstate_portfolio.map(get_first_price(_, i)))
}
*/
// (3) Complete the function below that obtains all first prices
// for the stock symbols from a portfolio (list of strings) and
// for the given range of years. The inner lists are for the
// stock symbols and the outer list for the years.
def get_prices(portfolio: List[String], years: Range): List[List[Option[Double]]] =
for (year <- years.toList) yield
for (symbol <- portfolio) yield get_first_price(symbol, year)
//test cases
//println("Task 3 data from Google and Apple in 2010 to 2012")
//val goog_aapl_prices = get_prices(List("GOOG", "AAPL"), 2010 to 2012)
//println(goog_aapl_prices.toString ++ "\n")
//val p_fb = get_prices(List("FB"), 2012 to 2014)
//val tt = get_prices(List("BIDU"), 2004 to 2008)
// (4) The function below calculates the change factor (delta) between
// a price in year n and a price in year n + 1.
def get_delta(price_old: Option[Double], price_new: Option[Double]) : Option[Double] = {
(price_old, price_new) match {
case (Some(x), Some(y)) => Some((y - x) / x)
case _ => None
}
}
// (5) The next function calculates all change factors for all prices (from a
// portfolio). The input to this function are the nested lists created by
// get_prices above.
def get_deltas(data: List[List[Option[Double]]]): List[List[Option[Double]]] =
for (i <- (0 until (data.length - 1)).toList) yield
for (j <- (0 until (data(0).length)).toList) yield get_delta(data(i)(j), data(i + 1)(j))
// test case using the prices calculated above
//println("Task 5 change prices from Google and Apple in 2010 and 2011")
//val goog_aapl_deltas = get_deltas(goog_aapl_prices)
//println(goog_aapl_deltas.toString ++ "\n")
//val ttd = get_deltas(tt)
// (6) Write a function that given change factors, a starting balance and an index,
// calculates the yearly yield, i.e. new balance, according to our dumb investment
// strategy. Index points to a year in the data list.
def yearly_yield(data: List[List[Option[Double]]], balance: Long, index: Int): Long = {
val somes = data(index).flatten
println(s"somes: $somes")
val somes_length = somes.length
if (somes_length == 0) balance
else {
val portion: Double = balance.toDouble / somes_length.toDouble
println(s"portion: $portion")
val b = balance + (for (x <- somes) yield (x * portion)).sum.toLong
println(s"balance $b")
println(s"profit ${(for (x <- somes) yield (x * portion)).sum}")
b
}
}
val dd = List(List(Some(0.9)), List(Some(0.9)))
yearly_yield(dd, 100, 0)
def yearly_yield2(data: List[List[Option[Double]]], balance: Long, index: Int) : Long = {
val share = balance/data(index).flatten.size.toDouble
println(s"portion: $share")
def count(data: List[Option[Double]], prof: Double, share: Double) : Double = data match{
case Nil => prof
case x::rest => count(rest,prof + (x.getOrElse(0.0) * share), share)
}
val balance_double = count(data(index), 0.0, share)
println(balance_double)
println(s"balance ${balance_double + balance}")
println(s"profit $balance_double")
//if (balance_double >= balance_double.toLong.toDouble+0.5) (balance_double + 1).toLong else balance_double.toLong
(balance_double.toLong + balance)
}
yearly_yield2(dd, 100, 0)
// test case using the deltas calculated above
//println("Task 6 yield from Google and Apple in 2010 with balance 100")
//val d0 = goog_aapl_deltas(0)(0)
//val d1 = goog_aapl_deltas(0)(1)
//println(s"50 * ${d0.get} + 50 * ${d1.get} = ${50.toDouble * d0.get + 50.toDouble * d1.get}")
//val goog_aapl_yield = yearly_yield(goog_aapl_deltas, 100, 0)
//val goog_aapl_yield = yearly_yield2(goog_aapl_deltas, 100, 0)
//println("Rounded yield: " ++ goog_aapl_yield.toString ++ "\n")
//yearly_yield(get_prices(rstate_portfolio, 2016 to 2018), 100, 2)
//get_prices(rstate_portfolio, 2016 to 2018)(2).flatten.sum
// (7) Write a function compound_yield that calculates the overall balance for a
// range of years where in each year the yearly profit is compounded to the new
// balances and then re-invested into our portfolio. For this use the function and
// results generated under (6). The function investment calls compound_yield
// with the appropriate deltas and the first index.
def compound_yield(data: List[List[Option[Double]]], balance: Long, index: Int): Long = {
if (index >= data.length) balance else {
val new_balance = yearly_yield(data, balance, index)
compound_yield(data, new_balance, index + 1)
}
}
def compound_yield2(data: List[List[Option[Double]]], balance: Long, index: Int): Long = {
if (index >= data.length) balance else {
val new_balance = yearly_yield2(data, balance, index)
compound_yield2(data, new_balance, index + 1)
}
}
def investment(portfolio: List[String], years: Range, start_balance: Long): Long = {
compound_yield(get_deltas(get_prices(portfolio, years)), start_balance, 0)
}
def investment2(portfolio: List[String], years: Range, start_balance: Long): Long = {
compound_yield2(get_deltas(get_prices(portfolio, years)), start_balance, 0)
}
//test cases for the two portfolios given above
println("Real data: " + investment(rstate_portfolio, 1978 to 2019, 100))
println("Blue data: " + investment(blchip_portfolio, 1978 to 2019, 100))
}
investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2000, 100)
investment2(List("GOOG", "AAPL", "BIDU"), 2000 to 2000, 100)
investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2001, 100)
investment2(List("GOOG", "AAPL", "BIDU"), 2000 to 2001, 100)
investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2002, 100)
investment2(List("GOOG", "AAPL", "BIDU"), 2000 to 2002, 100)
investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2003, 100)
investment2(List("GOOG", "AAPL", "BIDU"), 2000 to 2003, 100)
investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2004, 100)
investment2(List("GOOG", "AAPL", "BIDU"), 2000 to 2004, 100)
investment(List("GOOG", "AAPL", "BIDU"), 2000 to 2005, 100)
investment2(List("GOOG", "AAPL", "BIDU"), 2000 to 2005, 100)