├── .gitignore
├── .idea
    ├── .name
    ├── compiler.xml
    ├── misc.xml
    ├── modules.xml
    ├── scala_compiler.xml
    └── vcs.xml
├── .travis.yml
├── LICENSE
├── ParseIFTTStockEtf.iml
├── README.md
├── pom.xml
└── src
    ├── data
        ├── sjnk.csv
        └── txn-no_headers.csv
    └── main
        └── scala
            └── com
                └── quant
                    ├── Parse
                        ├── CsvUtil.scala
                        ├── GoogleFinanceParse.scala
                        └── IFTTTParse.scala
                    ├── StockEtfData.scala
                    ├── TechAnalysis
                        ├── Average.scala
                        └── Fibo.scala
                    └── Tree
                        ├── Sort.scala
                        └── Tree.scala
/.gitignore:
--------------------------------------------------------------------------------
 1 | # Scala Specific
 2 | *.class
 3 | *.log
 4 | 
 5 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
 6 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
 7 | 
 8 | # User-specific stuff:
 9 | .idea/**/workspace.xml
10 | .idea/**/tasks.xml
11 | .idea/dictionaries
12 | .idea/kotlinc.xml
13 | # Sensitive or high-churn files:
14 | .idea/**/dataSources/
15 | .idea/**/dataSources.ids
16 | .idea/**/dataSources.xml
17 | .idea/**/dataSources.local.xml
18 | .idea/**/sqlDataSources.xml
19 | .idea/**/dynamic.xml
20 | .idea/**/uiDesigner.xml
21 | 
22 | # Gradle:
23 | .idea/**/gradle.xml
24 | .idea/**/libraries
25 | 
26 | #Maven
27 | target/
28 | 
29 | # Mongo Explorer plugin:
30 | .idea/**/mongoSettings.xml
31 | 
32 | ## File-based project format:
33 | *.iws
34 | 
35 | target/
36 | 
37 | ## Plugin-specific files:
38 | 
39 | # IntelliJ
40 | /out/
41 | 
42 | # mpeltonen/sbt-idea plugin
43 | .idea_modules/
44 | 
45 | # JIRA plugin
46 | atlassian-ide-plugin.xml
47 | 
48 | # Cursive Clojure plugin
49 | .idea/replstate.xml
50 | 
51 | # Crashlytics plugin (for Android Studio and IntelliJ)
52 | com_crashlytics_export_strings.xml
53 | crashlytics.properties
54 | crashlytics-build.properties
55 | fabric.properties
56 | 
57 | # Windows thumbnail cache files
58 | Thumbs.db
59 | ehthumbs.db
60 | ehthumbs_vista.db
61 | 
62 | # Folder config file
63 | Desktop.ini
64 | 
65 | # Recycle Bin used on file shares
66 | $RECYCLE.BIN/
67 | 
68 | # Windows Installer files
69 | *.cab
70 | *.msi
71 | *.msm
72 | *.msp
73 | 
74 | # Windows shortcuts
75 | *.lnk
76 | 
77 | /lib
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | ParseIFTTStockEtf
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |       
 6 |         
 7 |         
 8 |         
 9 |         
10 |       
11 |     
12 |     
13 |       
14 |     
15 |   
16 | 
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 9 |   
10 |   
11 |     
12 |   
13 | 
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |   
4 |     
5 |       
6 |     
7 |   
8 | 
--------------------------------------------------------------------------------
/.idea/scala_compiler.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |       
 6 |         
 7 |         
 8 |       
 9 |     
10 |   
11 | 
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |   
4 |     
5 |   
6 | 
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | install: mvn install
2 | language: scala
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
 1 | MIT License
 2 | 
 3 | Copyright (c) 2017 Frank Cash
 4 | 
 5 | Permission is hereby granted, free of charge, to any person obtaining a copy
 6 | of this software and associated documentation files (the "Software"), to deal
 7 | in the Software without restriction, including without limitation the rights
 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 | 
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 | 
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/ParseIFTTStockEtf.iml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |       
 8 |       
 9 |       
10 |     
11 |     
12 |     
13 |     
14 |     
15 |     
16 |     
17 |     
18 |     
19 |     
20 |     
21 |     
22 |     
23 |     
24 |   
25 | 
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
 1 | # Scala Quant
 2 | 
 3 | This is a project to explore market data.
 4 | 
 5 | This project is designed to work with a specific IFTTT plugin: [Keep track of a particular stock's daily closing price in a spreadsheet](https://ifttt.com/applets/117304p-keep-track-of-a-particular-stock-s-daily-closing-price-in-a-spreadsheet)
 6 | 
 7 | This project is also designed to work with a CSV of historical data downloaded from Google Finance.
 8 | 
 9 | ## Utilizing
10 | 
11 | Download the `CSV` file for your desired Stock/ETF.
12 | 
13 | 
14 | ## Functions
15 | 
16 | `avgResistance(data:List[List[Double]]): Double`
17 | 
18 | Calculates the [average resistance](http://www.investopedia.com/articles/technical/061801.asp) based local maxes from split lists.  Takes maximum values from the split lists and then generates an average using the amount of split lists.
19 | 
20 | `avgSupport(data:List[List[Double]]): Double`
21 | 
22 | Calculates the [average support](http://www.investopedia.com/articles/technical/061801.asp) based local maxes from split lists.  Takes minimum values from the split lists and then generates an average using the amount of split lists.
23 | 
24 | `movingAvg(movingAvgSize:Double, data:List[Double] ): Double`
25 | 
26 | Calculates [moving average](http://www.investopedia.com/terms/m/movingaverage.asp).  The amount of days is pre-defined to 10.
27 | 
28 | `fibRetracementValues(high:Double, low:Double): List[Double]`
29 | 
30 | Calculates [Fibonacci Retracement](http://www.investopedia.com/ask/answers/05/fibonacciretracement.asp) values for the given high and low.  Predefined ratios for the retracement values are: 23.6%, 38.2%, 50.0%, 0.618%, 100%.
31 | 
32 | ## Configuration
33 | 
34 | It is also able to configure how many days should be grouped into the lists for calculating the average resistance and support.  Edit `final val step = 5`.
35 | 
36 | The moving average size can be changed. Edit `  final val movingAvgSize = 10`
37 | 
38 | ### License
39 | 
40 | MIT
41 | 
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  5 |     4.0.0
  6 |     quant.com.scalastock
  7 |     ParseIFTTStockEtf
  8 |     1.0-SNAPSHOT
  9 |     
 10 |         2.11.8
 11 |         2.2.0
 12 |         1.7
 13 |         1.7
 14 |     
 15 |     
 16 |         
 17 |             org.scalatest
 18 |             scalatest_2.10
 19 |             ${scalaTest.version}
 20 |             test
 21 |         
 22 |         
 23 |             org.scala-lang
 24 |             scala-library
 25 |             ${scala.version}
 26 |         
 27 |         
 28 |             org.pegdown
 29 |             pegdown
 30 |             1.2.1
 31 |             test
 32 |         
 33 |         
 34 |             junit
 35 |             junit
 36 |             4.8.1
 37 |             test
 38 |         
 39 |     
 40 |     
 41 |         
 42 |             
 43 |                 org.scala-tools
 44 |                 maven-scala-plugin
 45 |                 2.15.2
 46 |                 
 47 |                     
 48 |                         scala-compile
 49 |                         
 50 |                             compile
 51 |                             testCompile
 52 |                         
 53 |                         
 54 |                             
 55 |                                 -dependencyfile
 56 |                                 ${project.build.directory}/.scala_dependencies
 57 |                             
 58 |                         
 59 |                     
 60 |                 
 61 |             
 62 |             
 76 |             
 77 |                 org.scalatest
 78 |                 scalatest-maven-plugin
 79 |                 1.0-M2
 80 |                 
 81 |                     ${project.build.directory}/surefire-reports
 82 |                     W 
 83 |                 
 84 |                 
 85 |                     
 86 |                         scala-test
 87 |                         
 88 |                             test
 89 |                         
 90 |                     
 91 |                 
 92 |             
 93 |         
 94 |     
 95 |     
 96 |         
 97 |             
 98 |                 net.alchim31.maven
 99 |                 scala-maven-plugin
100 |             
101 |         
102 |     
103 | 
104 | 
--------------------------------------------------------------------------------
/src/data/sjnk.csv:
--------------------------------------------------------------------------------
 1 | "February 24 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,28.11,http://finance.yahoo.com/q?s=SJNK,"February 24, 2017"
 2 | "February 27 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,28.13,http://finance.yahoo.com/q?s=SJNK,"February 27, 2017"
 3 | "February 28 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,28.14,http://finance.yahoo.com/q?s=SJNK,"February 28, 2017"
 4 | "March 01 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,28.09,http://finance.yahoo.com/q?s=SJNK,"March 01, 2017"
 5 | "March 02 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,28.04,http://finance.yahoo.com/q?s=SJNK,"March 02, 2017"
 6 | "March 03 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,28.06,http://finance.yahoo.com/q?s=SJNK,"March 03, 2017"
 7 | "March 06 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.97,http://finance.yahoo.com/q?s=SJNK,"March 06, 2017"
 8 | "March 07 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.88,http://finance.yahoo.com/q?s=SJNK,"March 07, 2017"
 9 | "March 08 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.77,http://finance.yahoo.com/q?s=SJNK,"March 08, 2017"
10 | "March 09 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.69,http://finance.yahoo.com/q?s=SJNK,"March 09, 2017"
11 | "March 10 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.695,http://finance.yahoo.com/q?s=SJNK,"March 10, 2017"
12 | "March 13 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.71,http://finance.yahoo.com/q?s=SJNK,"March 13, 2017"
13 | "March 14 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.65,http://finance.yahoo.com/q?s=SJNK,"March 14, 2017"
14 | "March 15 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.89,http://finance.yahoo.com/q?s=SJNK,"March 15, 2017"
15 | "March 16 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.785,http://finance.yahoo.com/q?s=SJNK,"March 16, 2017"
16 | "March 17 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.8,http://finance.yahoo.com/q?s=SJNK,"March 17, 2017"
17 | "March 20 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.785,http://finance.yahoo.com/q?s=SJNK,"March 20, 2017"
18 | "March 21 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.6556,http://finance.yahoo.com/q?s=SJNK,"March 21, 2017"
19 | "March 22 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.715,http://finance.yahoo.com/q?s=SJNK,"March 22, 2017"
20 | "March 23 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.695,http://finance.yahoo.com/q?s=SJNK,"March 23, 2017"
21 | "March 24 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.775,http://finance.yahoo.com/q?s=SJNK,"March 24, 2017"
22 | "March 27 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.79,http://finance.yahoo.com/q?s=SJNK,"March 27, 2017"
23 | "March 28 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.87,http://finance.yahoo.com/q?s=SJNK,"March 28, 2017"
24 | "March 29 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.89,http://finance.yahoo.com/q?s=SJNK,"March 29, 2017"
25 | "March 30 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.975,http://finance.yahoo.com/q?s=SJNK,"March 30, 2017"
26 | "March 31 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.95,http://finance.yahoo.com/q?s=SJNK,"March 31, 2017"
27 | "April 03 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.82,http://finance.yahoo.com/q?s=SJNK,"April 03, 2017"
28 | "April 04 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.84,http://finance.yahoo.com/q?s=SJNK,"April 04, 2017"
29 | "April 05 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.82,http://finance.yahoo.com/q?s=SJNK,"April 05, 2017"
30 | "April 06 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.8545,http://finance.yahoo.com/q?s=SJNK,"April 06, 2017"
31 | "April 07 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.8557,http://finance.yahoo.com/q?s=SJNK,"April 07, 2017"
32 | "April 10 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.89,http://finance.yahoo.com/q?s=SJNK,"April 10, 2017"
33 | "April 11 2017",SPDR Blmbg BarclaysST HY Bd ETF,SJNK,27.88,http://finance.yahoo.com/q?s=SJNK,"April 11, 2017"
--------------------------------------------------------------------------------
/src/data/txn-no_headers.csv:
--------------------------------------------------------------------------------
 1 | 5/1/2017,79.25,79.5,78.4,79.29,5065496
 2 | 4/28/2017,81.04,81.04,78.65,79.18,10522503
 3 | 4/27/2017,80.75,81.27,80.36,80.8,5762688
 4 | 4/26/2017,82.17,82.92,80.79,81.11,6763868
 5 | 4/25/2017,81.3,82.43,81.12,82.36,7604096
 6 | 4/24/2017,81.02,81.51,80.85,81.08,5129198
 7 | 4/21/2017,79.58,80.41,79.24,79.81,6314436
 8 | 4/20/2017,79.72,80.89,79.51,80.76,3586302
 9 | 4/19/2017,79.96,80.66,79.28,79.37,4673843
10 | 4/18/2017,78.51,79.84,78.35,79.61,4529140
11 | 4/17/2017,78.3,78.75,78.12,78.72,4462363
12 | 4/13/2017,78.47,79.33,77.83,77.84,4658269
13 | 
--------------------------------------------------------------------------------
/src/main/scala/com/quant/Parse/CsvUtil.scala:
--------------------------------------------------------------------------------
 1 | package com.quant.Parse
 2 | 
 3 | import scala.collection.mutable.ArrayBuffer
 4 | 
 5 | /**
 6 |   * Created by Frank Cash on 5/2/17.
 7 |   */
 8 | object CsvUtil {
 9 |   /**
10 |     *
11 |     * @param path Path to CSV File
12 |     * @return ArrayBuffer
13 |     */
14 |   def CSVParseIFTTT(path: String): ArrayBuffer[Array[String]] ={
15 |     val rows = ArrayBuffer[Array[String]]()
16 |     val bufferedSource = io.Source.fromFile(path)
17 |     for(line <- bufferedSource.getLines()){
18 |       rows += line.split(",").map(_.trim)
19 |     }
20 |     bufferedSource.close()
21 |     rows
22 |   }
23 | 
24 |   /**
25 |     *
26 |     * @param xs List
27 |     * @param n Step size
28 |     * @tparam A
29 |     * @return Returns a list of stepped lists
30 |     */
31 |   def split[A](xs:List[A], n:Int): List[List[A]] ={
32 |     if(xs.isEmpty) Nil
33 |     else (xs take n) :: split(xs drop n, n)
34 |   }
35 | 
36 | }
37 | 
--------------------------------------------------------------------------------
/src/main/scala/com/quant/Parse/GoogleFinanceParse.scala:
--------------------------------------------------------------------------------
 1 | package com.quant.Parse
 2 | 
 3 | import scala.collection.mutable.ArrayBuffer
 4 | 
 5 | /**
 6 |   * Created by Frank Cash on 5/2/17.
 7 |   */
 8 | object GoogleFinanceParse {
 9 | 
10 |   /**
11 |     *
12 |     * @param rows Rows from CSVParse Output
13 |     * @return ArrayBuffer with Closing Costs of the Stock/ETF
14 |     */
15 |   def StripClosingPriceGoog(rows: ArrayBuffer[Array[String]]): ArrayBuffer[Double] ={
16 |     val closingCosts:ArrayBuffer[Double] = new ArrayBuffer[Double]
17 |     rows.map(row => closingCosts.append(row(4).toDouble))
18 |     closingCosts
19 |   }
20 | }
21 | 
--------------------------------------------------------------------------------
/src/main/scala/com/quant/Parse/IFTTTParse.scala:
--------------------------------------------------------------------------------
 1 | package com.quant.Parse
 2 | 
 3 | import scala.collection.mutable.ArrayBuffer
 4 | 
 5 | /**
 6 |   * Created by Frank Cash on 5/2/17.
 7 |   */
 8 | object IFTTTParse {
 9 | 
10 | 
11 |   /**
12 |     *
13 |     * @param rows Rows from CSVParse Output
14 |     * @return ArrayBuffer with Closing Costs of the Stock/ETF
15 |     */
16 |   def StripClosingPriceIFTTT(rows: ArrayBuffer[Array[String]]): ArrayBuffer[Double] ={
17 |     val closingCosts:ArrayBuffer[Double] = new ArrayBuffer[Double]
18 |     rows.map(row => closingCosts.append(row(3).toDouble))
19 |     closingCosts
20 |   }
21 | 
22 | }
23 | 
--------------------------------------------------------------------------------
/src/main/scala/com/quant/StockEtfData.scala:
--------------------------------------------------------------------------------
 1 | /**MIT License
 2 |   *Copyright (c) 2017 Frank Cash
 3 |   *Permission is hereby granted, free of charge, to any person obtaining a copy
 4 |   *of this software and associated documentation files (the "Software"), to deal
 5 |   *in the Software without restriction, including without limitation the rights
 6 |   *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 7 |   *copies of the Software, and to permit persons to whom the Software is
 8 |   *furnished to do so, subject to the following conditions:
 9 |   *The above copyright notice and this permission notice shall be included in all
10 |   *copies or substantial portions of the Software.
11 |   *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12 |   *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 |   *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14 |   *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15 |   *LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16 |   *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17 |   *SOFTWARE.
18 |   */
19 | 
20 | /**
21 |   * Created by Frank Cash on 4/12/2017.
22 |   * Made to work CSV output from: https://ifttt.com/applets/117304p-keep-track-of-a-particular-stock-s-daily-closing-price-in-a-spreadsheet
23 |   */
24 | 
25 | import com.quant.TechAnalysis.{Average, Fibo}
26 | import Tree.{Sort, Tree}
27 | import com.quant.Parse.{CsvUtil, GoogleFinanceParse, IFTTTParse}
28 | 
29 | 
30 | object StockEtfData {
31 | 
32 |   /**
33 |     * Step for calculating segmentation of price data when calculating local min and max for historical support and resistance
34 |     */
35 |   final val step = 5
36 |   /**
37 |     * Amount of days to use for Moving Average
38 |     */
39 |   final val movingAvgSize = 10
40 | 
41 | 
42 | 
43 |   def IFTTT(path:String ): Unit= {
44 |     println("hello World")
45 |     val rows = CsvUtil.CSVParseIFTTT(path)
46 |     val closingPrices = IFTTTParse.StripClosingPriceIFTTT(rows)
47 |     val sorted = Sort.mergeSort(closingPrices.toList)
48 |     val myTree = Tree.fromSortedList(sorted)
49 |     val steppedClosingPrices = CsvUtil.split(closingPrices.toList, step)
50 |     val mvAvg = Average.movingAvg(movingAvgSize.toDouble, closingPrices.takeRight(movingAvgSize.toInt).toList)
51 |     val retracementLevels = Fibo.fibRetracementValues(myTree.max, myTree.min)
52 |     println("Moving Average is: "+ mvAvg)
53 | 
54 |     println("Average Support: " + Average.avgSupport(steppedClosingPrices))
55 |     println("Average Resistance: " + Average.avgResistance(steppedClosingPrices))
56 | 
57 | 
58 |     println("Historical Low: " + myTree.min)
59 |     println("Historical Max: " + myTree.max)
60 |     retracementLevels.map(l => println("Retracement: " + l))
61 | 
62 | 
63 |   }
64 | 
65 |   def Goog(path:String ): Unit= {
66 |     val rows = CsvUtil.CSVParseIFTTT(path)
67 |     val closingPrices = GoogleFinanceParse.StripClosingPriceGoog(rows)
68 |     val sorted = Sort.mergeSort(closingPrices.toList)
69 |     val myTree = Tree.fromSortedList(sorted)
70 |     val steppedClosingPrices = CsvUtil.split(closingPrices.toList, step)
71 |     val mvAvg = Average.movingAvg(movingAvgSize.toDouble, closingPrices.takeRight(movingAvgSize.toInt).toList)
72 |     val retracementLevels = Fibo.fibRetracementValues(myTree.max, myTree.min)
73 |     println("Moving Average is: "+ mvAvg)
74 | 
75 |     println("Average Support: " + Average.avgSupport(steppedClosingPrices))
76 |     println("Average Resistance: " + Average.avgResistance(steppedClosingPrices))
77 | 
78 | 
79 |     println("Historical Low: " + myTree.min)
80 |     println("Historical Max: " + myTree.max)
81 |     retracementLevels.map(l => println("Retracement: " + l))
82 |   }
83 | 
84 |   def main(args: Array[String]): Unit= {
85 |     IFTTT("/Users/majora/Code/Scala-Quant/src/data/sjnk.csv")
86 |     Goog("/Users/majora/Code/Scala-Quant/src/data/txn-no_headers.csv")
87 |   }
88 | 
89 | 
90 |   }
91 | 
--------------------------------------------------------------------------------
/src/main/scala/com/quant/TechAnalysis/Average.scala:
--------------------------------------------------------------------------------
 1 | package com.quant.TechAnalysis
 2 | 
 3 | /**
 4 |   * Created by Frank Cash on 5/6/17.
 5 |   */
 6 | object Average {
 7 | 
 8 |   /**
 9 |     * Reference on Resistance 
10 |     * @param data List of List Double.  Takes return from split(xs, n).
11 |     * @return Returns the avg resistance
12 |     */
13 |   def avgResistance(data:List[List[Double]]): Double = {
14 |     var runTotal = 0.0;
15 |     for(n <- data){
16 |       runTotal += (n.max)
17 |     }
18 |     return runTotal./(data.length)
19 |   }
20 | 
21 | 
22 |   /**
23 |     * Reference on Support 
24 |     * @param data List of List Double. Takes return from split(xs, n)
25 |     * @return Returns the avg support
26 |     */
27 |   def avgSupport(data:List[List[Double]]): Double ={
28 |     var runTotal = 0.0
29 |     for(n <- data){
30 |       runTotal += n.min
31 |     }
32 |     return runTotal./(data.length)
33 |   }
34 | 
35 | 
36 |   /**
37 |     * Reference on Moving Average 
38 |     * @param data List[Double] of prices to include in moving average
39 |     * @return Moving Average
40 |     */
41 |   def movingAvg(movingAvgSize:Double, data:List[Double] ): Double ={
42 |     var avg = 0.0
43 |     avg = data.sum / movingAvgSize
44 |     return avg
45 |   }
46 | 
47 | }
48 | 
--------------------------------------------------------------------------------
/src/main/scala/com/quant/TechAnalysis/Fibo.scala:
--------------------------------------------------------------------------------
 1 | package com.quant.TechAnalysis
 2 | 
 3 | import scala.collection.mutable.ArrayBuffer
 4 | 
 5 | /**
 6 |   * Created by Frank Cash on 5/6/17.
 7 |   */
 8 | object Fibo {
 9 |   /**
10 |     * Fibonacci Retracement Math
11 |     * High minus Low multiplied by the given ratio
12 |     * Reference on Fibonacci Retracement 
13 |     * @param h The high value
14 |     * @param l The low value
15 |     * @param ratio The ratio to use, as a decimal
16 |     * @return the amount for the fibonacci retracement at the given ratio
17 |     */
18 |   def fibonacciRetracement(h:Double, l:Double, ratio:Double): Double={
19 |     val fib = (h - l) * ratio
20 |     val res = h - fib
21 |     res
22 |   }
23 | 
24 |   /**
25 |     * Reference on Fibonacci Retracement 
26 |     * @param high
27 |     * @param low
28 |     * @return List of fibonacci retracement values for [23.6%, 38.2%, 50.0%, 0.618%, 100%]
29 |     */
30 |   def fibRetracementValues(high:Double, low:Double): List[Double]={
31 |     val fib:ArrayBuffer[Double] = new ArrayBuffer[Double]
32 |     fib.append(fibonacciRetracement(high, low, 0.236))
33 |     fib.append(fibonacciRetracement(high, low, 0.382))
34 |     fib.append(fibonacciRetracement(high, low, 0.500))
35 |     fib.append(fibonacciRetracement(high, low, 0.618))
36 |     fib.append(fibonacciRetracement(high, low, 1.000))
37 |     fib.toList
38 | 
39 |   }
40 | }
41 | 
--------------------------------------------------------------------------------
/src/main/scala/com/quant/Tree/Sort.scala:
--------------------------------------------------------------------------------
 1 | /**MIT License
 2 |   *Copyright (c) 2017 Frank Cash
 3 |   *Permission is hereby granted, free of charge, to any person obtaining a copy
 4 |   *of this software and associated documentation files (the "Software"), to deal
 5 |   *in the Software without restriction, including without limitation the rights
 6 |   *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 7 |   *copies of the Software, and to permit persons to whom the Software is
 8 |   *furnished to do so, subject to the following conditions:
 9 |   *The above copyright notice and this permission notice shall be included in all
10 |   *copies or substantial portions of the Software.
11 |   *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12 |   *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 |   *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14 |   *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15 |   *LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16 |   *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17 |   *SOFTWARE.
18 |   */
19 | 
20 | package Tree
21 | 
22 | 
23 | /**
24 |   * Created by Frank Cash on 4/16/17.
25 |   */
26 | 
27 | object Sort{
28 | 
29 |   /**
30 |     *
31 |     * @param left List[Double]
32 |     * @param right List[Double]
33 |     * @return List[Double]
34 |     */
35 |     def merge(left: List[Double], right: List[Double]):List[Double]= (left, right)match{
36 |       case(left, Nil) => left
37 |       case(Nil, right) => right
38 |       case(leftHead :: leftTail, rightHead :: rightTail) =>
39 |         if(leftHead < rightHead) leftHead::merge(leftTail, right)
40 |         else rightHead :: merge(left, rightTail)
41 |     }
42 | 
43 |   /**
44 |     *  Merge Sort
45 |     * @param list[Double] Input
46 |     * @return Returns a sorted List[Double]
47 |     */
48 |   def mergeSort(list: List[Double]): List[Double] ={
49 |       val n = list.length / 2
50 |       if (n == 0) list
51 |       else{
52 |         val(left, right) = list.splitAt(n)
53 |         merge(mergeSort(left), mergeSort(right))
54 |       }
55 |     }
56 | 
57 | 
58 |   }
59 | 
60 | 
--------------------------------------------------------------------------------
/src/main/scala/com/quant/Tree/Tree.scala:
--------------------------------------------------------------------------------
  1 | /**MIT License
  2 |   *Copyright (c) 2017 Frank Cash
  3 |   *Permission is hereby granted, free of charge, to any person obtaining a copy
  4 |   *of this software and associated documentation files (the "Software"), to deal
  5 |   *in the Software without restriction, including without limitation the rights
  6 |   *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7 |   *copies of the Software, and to permit persons to whom the Software is
  8 |   *furnished to do so, subject to the following conditions:
  9 |   *The above copyright notice and this permission notice shall be included in all
 10 |   *copies or substantial portions of the Software.
 11 |   *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 12 |   *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 13 |   *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 14 |   *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 15 |   *LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 16 |   *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 17 |   *SOFTWARE.
 18 |   */
 19 | 
 20 | package Tree
 21 | 
 22 | /**
 23 |   * Frank Cash
 24 |   * Implementation based upon Scalacaster BST 
 25 |   */
 26 | 
 27 | abstract sealed class Tree[+A <% Ordered[A]] {
 28 | 
 29 |   /**
 30 |     * The value of this tree.
 31 |     */
 32 |   def value: A
 33 | 
 34 |   /**
 35 |     * The left child of this tree.
 36 |     */
 37 |   def left: Tree[A]
 38 | 
 39 |   /**
 40 |     * The right child of this tree.
 41 |     */
 42 |   def right: Tree[A]
 43 | 
 44 |   /**
 45 |     * The size of this tree.
 46 |     */
 47 |   def size: Int
 48 | 
 49 |   /**
 50 |     * Checks whether this tree is empty or not.
 51 |     */
 52 |   def isEmpty: Boolean
 53 | 
 54 | 
 55 |   def isValid: Boolean =
 56 |     if (isEmpty) true
 57 |     else if (left.isEmpty && right.isEmpty) true
 58 |     else if (left.isEmpty) right.value >= value && right.isValid
 59 |     else if (right.isEmpty) left.value <= value && left.isValid
 60 |     else left.value <= value && right.value >= value && left.isValid && right.isValid
 61 | 
 62 | 
 63 |   def isBalanced: Boolean = {
 64 |     def loop(t: Tree[A]): Int =
 65 |       if (t.isEmpty) 0
 66 |       else {
 67 |         val l = loop(t.left)
 68 |         if (l == -1) -1
 69 |         else {
 70 |           val r = loop(t.right)
 71 |           if (r == -1) -1
 72 |           else if (math.abs(l - r) > 1) -1
 73 |           else 1 + math.max(l, r)
 74 |         }
 75 |       }
 76 | 
 77 |     !(loop(this) == -1)
 78 |   }
 79 | 
 80 | 
 81 |   def add[B >: A <% Ordered[B]](x: B): Tree[B] =
 82 |     if (isEmpty) Tree.make(x)
 83 |     else if (x < value) Tree.make(value, left.add(x), right)
 84 |     else if (x > value) Tree.make(value, left, right.add(x))
 85 |     else this
 86 | 
 87 | 
 88 | 
 89 | 
 90 | 
 91 |   def contains[B >: A <% Ordered[B]](x: B): Boolean = {
 92 |     def loop(t: Tree[A], c: Option[A]): Boolean =
 93 |       if (t.isEmpty) check(c)
 94 |       else if (x < t.value) loop(t.left, c)
 95 |       else loop(t.right, Some(t.value))
 96 | 
 97 |     def check(c: Option[A]): Boolean = c match {
 98 |       case Some(y) if y == x => true
 99 |       case _ => false
100 |     }
101 | 
102 |     loop(this, None)
103 |   }
104 | 
105 | 
106 |   def foreach(f: (A) => Unit): Unit =
107 |     if (!isEmpty) {
108 |       left.foreach(f)
109 |       f(value)
110 |       right.foreach(f)
111 |     }
112 | 
113 |   def map[B <% Ordered[B]](f: (A) => B): Tree[B] =
114 |     if (isEmpty) Tree.empty
115 |     else Tree.make(f(value), left.map(f), right.map(f))
116 | 
117 | 
118 |   /**
119 |     * Searches for the minimal element of this tree.
120 |     */
121 |   def min: A = {
122 |     def loop(t: Tree[A], m: A): A =
123 |       if (t.isEmpty) m
124 |       else loop(t.left, t.value)
125 | 
126 |     if (isEmpty) fail("An empty tree.")
127 |     else loop(left, value)
128 |   }
129 | 
130 |   /**
131 |     * Searches for the maximal element of this tree.
132 |     */
133 |   def max: A = {
134 |     def loop(t: Tree[A], m: A): A =
135 |       if (t.isEmpty) m
136 |       else loop(t.right, t.value)
137 | 
138 |     if (isEmpty) fail("An empty tree.")
139 |     else loop(right, value)
140 |   }
141 | 
142 |   /**
143 |     * Calculates the height of this tree.
144 |     */
145 |   def height: Int =
146 |     if (isEmpty) 0
147 |     else 1 + math.max(left.height, right.height)
148 | 
149 | 
150 | 
151 |   /**
152 |     * Searches for the successor of given element 'x'.
153 |     */
154 |   def successor[B >: A <% Ordered[B]](x: B): A = {
155 |     def forward(t: Tree[A], p: List[Tree[A]]): A =
156 |       if (t.isEmpty) fail("Can't find " + x + " in this tree.")
157 |       else if (x < t.value) forward(t.left, t :: p)
158 |       else if (x > t.value) forward(t.right, t :: p)
159 |       else if (!t.right.isEmpty) t.right.min
160 |       else backward(t, p)
161 | 
162 |     def backward(t: Tree[A], p: List[Tree[A]]): A =
163 |       if (p.isEmpty) fail("The " + x + " doesn't have an successor.")
164 |       else if (t == p.head.right) backward(p.head, p.tail)
165 |       else p.head.value
166 | 
167 |     forward(this, Nil)
168 |   }
169 | 
170 | 
171 | 
172 |   /**
173 |     * Searches for the lower bound element of given 'x'.
174 |     */
175 |   def lowerBound[B >: A <% Ordered[B]](x: B): A =
176 |     if (isEmpty) fail("Tree is empty.")
177 |     else if (x < value)
178 |       if (!left.isEmpty) left.lowerBound(x)
179 |       else value
180 |     else if (x > value)
181 |       if (!right.isEmpty) { val v = right.lowerBound(x); if (v > x) value else v }
182 |       else value
183 |     else value
184 | 
185 |   /**
186 |     * Calculates the number of elements that less or equal to given 'x'.
187 |     */
188 |   def rank[B >: A <% Ordered[B]](x: B): Int =
189 |     if (isEmpty) 0
190 |     else if (x < value) left.rank(x)
191 |     else if (x > value) 1 + left.size + right.rank(x)
192 |     else left.size
193 | 
194 |   /**
195 |     * Searches for the upper bound element of given 'x'.
196 |     */
197 |   def upperBound[B >: A <% Ordered[B]](x: B): A =
198 |     if (isEmpty) fail("Tree is empty.")
199 |     else if (x < value)
200 |       if (!left.isEmpty) { val v = left.upperBound(x); if (v < x) value else v }
201 |       else value
202 |     else if (x > value)
203 |       if (!right.isEmpty) right.upperBound(x)
204 |       else value
205 |     else value
206 | 
207 |   /**
208 |     * Calculates the path for given element 'x'.
209 |     */
210 |   def path[B >: A <% Ordered[B]](x: B): List[Tree[A]] =
211 |     if (isEmpty) fail("Can't find " + x + " in this tree.")
212 |     else if (x < value) this :: left.path(x)
213 |     else if (x > value) this :: right.path(x)
214 |     else List(this)
215 | 
216 | 
217 |   /**
218 |     * Performs the DFS and dumps values to the list.
219 |     */
220 |   def valuesByDepth: List[A] = {
221 |     def loop(s: List[Tree[A]]): List[A] =
222 |       if (s.isEmpty) Nil
223 |       else if (s.head.isEmpty) loop(s.tail)
224 |       else s.head.value :: loop(s.head.right :: s.head.left :: s.tail)
225 | 
226 |     loop(List(this))
227 |   }
228 | 
229 |   /**
230 |     * Fails with given message 'm'.
231 |     */
232 |   def fail(m: String) = throw new NoSuchElementException(m)
233 | }
234 | 
235 | case object Leaf extends Tree[Nothing] {
236 |   def value: Nothing = fail("An empty tree.")
237 |   def left: Tree[Nothing] = fail("An empty tree.")
238 |   def right: Tree[Nothing] = fail("An empty tree.")
239 |   def size: Int = 0
240 | 
241 |   def isEmpty: Boolean = true
242 | }
243 | 
244 | case class Branch[A <% Ordered[A]](value: A,
245 |                                    left: Tree[A],
246 |                                    right: Tree[A],
247 |                                    size: Int) extends Tree[A] {
248 |   def isEmpty: Boolean = false
249 | }
250 | 
251 | object Tree {
252 | 
253 |   /**
254 |     * An empty tree.
255 |     */
256 |   def empty[A]: Tree[A] = Leaf
257 | 
258 |   /**
259 |     * A smart constructor for tree's branch.
260 |     */
261 |   def make[A <% Ordered[A]](x: A, l: Tree[A] = Leaf, r: Tree[A] = Leaf): Tree[A] =
262 |     Branch(x, l, r, l.size + r.size + 1)
263 | 
264 |   /**
265 |     * Creates a new tree from given sequence 'xs'.
266 |     */
267 |   def apply[A <% Ordered[A]](xs: A*): Tree[A] = {
268 |     var r: Tree[A] = Tree.empty
269 |     for (x <- xs) r = r.add(x)
270 |     r
271 |   }
272 | 
273 |   /**
274 |     * Creates a new balanced tree from given sorted array 'a'.
275 |     */
276 |   def fromSortedArray[A <% Ordered[A]](a: Array[A]): Tree[A] = {
277 |     def loop(l: Int, r: Int): Tree[A] =
278 |       if (l == r) Tree.empty
279 |       else {
280 |         val p = (l + r) / 2
281 |         Tree.make(a(p), loop(l, p), loop(p + 1, r))
282 |       }
283 | 
284 |     loop(0, a.length)
285 |   }
286 | 
287 |   /**
288 |     * Creates a new balanced tree from given sorted list 'l'.
289 |     *
290 |     * http://www.geeksforgeeks.org/sorted-linked-list-to-balanced-bst/
291 |     */
292 |   def fromSortedList[A <% Ordered[A]](l: List[A]): Tree[A] = {
293 |     def loop(ll: List[A], n: Int): (List[A], Tree[A]) =
294 |       if (n == 0) (ll, Tree.empty)
295 |       else {
296 |         val (lt, left) = loop(ll, n / 2)
297 |         val (rt, right) = loop(lt.tail, n - 1 - n / 2)
298 |         (rt, Tree.make(lt.head, left, right))
299 |       }
300 | 
301 |     loop(l, l.length)._2
302 |   }
303 | 
304 | }
305 | 
--------------------------------------------------------------------------------