main_solution1/drumb.scala
author Christian Urban <christian.urban@kcl.ac.uk>
Thu, 04 Aug 2022 16:53:38 +0200
changeset 426 b51467741af2
parent 418 fa7f7144f2bb
child 431 ef68136b9a96
permissions -rw-r--r--
updated

// 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)