-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
380 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#load @"C:\ExcelEnv.fsx" | ||
#load @"C:\StocksScript.fsx" | ||
open StockScript | ||
open System | ||
open System.Net | ||
open Microsoft.Office.Interop.Excel | ||
|
||
|
||
let now = System.DateTime.Now | ||
|
||
let chart = Excel.NewChart().Value | ||
|
||
let msft = read ("MSFT", now.AddMonths(-6), now) | ||
chart |> addStockHistory msft | ||
chart |> addMovingAverages msft | ||
|
||
chart |> clear | ||
|
||
for stock in ["AAPL";"MSFT";"GOOG"] do | ||
chart |> addStockHistory (read (stock, now.AddMonths(-6), now)) | ||
chart |> addMovingAverages (read (stock, now.AddMonths(-6), now)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,205 @@ | ||
module Excel | ||
//Written by Mathias Brandewinder (Twitter: @brandewinder Blog: http://www.clear-lines.com/blog/) | ||
#r @"C:\Program Files (x86)\Microsoft Visual Studio 11.0\Visual Studio Tools for Office\PIA\Office14\office.dll" | ||
#r @"C:\Program Files (x86)\Microsoft Visual Studio 11.0\Visual Studio Tools for Office\PIA\Office14\Microsoft.Office.Interop.Excel.dll" | ||
|
||
open Microsoft.Office.Interop.Excel | ||
open System.Runtime.InteropServices | ||
|
||
// Attach to the running instance of Excel, if any | ||
let Attach () = | ||
try | ||
Marshal.GetActiveObject("Excel.Application") | ||
:?> Microsoft.Office.Interop.Excel.Application | ||
|> Some | ||
with | ||
| _ -> | ||
printfn "Could not find running instance of Excel" | ||
None | ||
|
||
// Find the Active workbook, if any | ||
let Active () = | ||
let xl = Attach () | ||
match xl with | ||
| None -> None | ||
| Some(xl) -> | ||
try | ||
xl.ActiveWorkbook |> Some | ||
with | ||
| _ -> | ||
printfn "Could not find active workbook" | ||
None | ||
|
||
let private flatten (arr: string [,]) = | ||
let iMax = Array2D.length1 arr | ||
let jMax = Array2D.length2 arr | ||
[| for i in 1 .. iMax -> | ||
[| for j in 1 .. jMax -> arr.[i,j] |] |] | ||
|
||
// Grab Selected Range, if any | ||
let Selection () = | ||
let xl = Attach () | ||
match xl with | ||
| None -> None | ||
| Some(xl) -> | ||
try | ||
let selection = xl.Selection :?> Range | ||
selection.Value2 :?> System.Object [,] | ||
|> Array2D.map (fun e -> e.ToString()) | ||
|> flatten |> Some | ||
with | ||
| _ -> | ||
printfn "Invalid active selection" | ||
None | ||
|
||
// Create a new Chart in active workbook | ||
let NewChart () = | ||
let wb = Active () | ||
match wb with | ||
| None -> | ||
printfn "No workbook" | ||
None | ||
| Some(wb) -> | ||
try | ||
let charts = wb.Charts | ||
charts.Add () :?> Chart |> Some | ||
with | ||
| _ -> | ||
printfn "Failed to create chart" | ||
None | ||
|
||
// Plots single-argument function(s) over an interval | ||
type Plot (f: float -> float, over: float * float) = | ||
let mutable functions = [ f ] | ||
let mutable over = over | ||
let mutable grain = 50 | ||
let chart = NewChart () | ||
let values () = | ||
let min, max = over | ||
let step = (max - min) / (float)grain | ||
[| min .. step .. max |] | ||
let draw f = | ||
match chart with | ||
| None -> ignore () | ||
| Some(chart) -> | ||
let seriesCollection = chart.SeriesCollection() :?> SeriesCollection | ||
let series = seriesCollection.NewSeries() | ||
let xValues = values () | ||
series.XValues <- xValues | ||
series.Values <- xValues |> Array.map f | ||
let redraw () = | ||
match chart with | ||
| None -> ignore () | ||
| Some(chart) -> | ||
let seriesCollection = chart.SeriesCollection() :?> SeriesCollection | ||
for s in seriesCollection do s.Delete() |> ignore | ||
functions |> List.iter (fun f -> draw f) | ||
|
||
do | ||
match chart with | ||
| None -> ignore () | ||
| Some(chart) -> | ||
chart.ChartType <- XlChartType.xlXYScatter | ||
let seriesCollection = chart.SeriesCollection() :?> SeriesCollection | ||
draw f | ||
|
||
member this.Add(f: float -> float) = | ||
match chart with | ||
| None -> ignore () | ||
| Some(chart) -> | ||
functions <- f :: functions | ||
draw f | ||
|
||
member this.Rescale(min, max) = | ||
over <- (min, max) | ||
redraw() | ||
|
||
member this.Zoom(zoom: int) = | ||
grain <- zoom | ||
redraw() | ||
|
||
// Plots surface of 2-argument function | ||
type Surface (f: float -> float -> float, xOver: (float * float), yOver: (float * float)) = | ||
let mutable xOver, yOver = xOver, yOver | ||
let mutable grain = 20 | ||
let chart = NewChart () | ||
let values over = | ||
let min, max = over | ||
let step = (max - min) / (float)grain | ||
[| min .. step .. max |] | ||
|
||
let redraw () = | ||
match chart with | ||
| None -> ignore () | ||
| Some(chart) -> | ||
let xl = chart.Application | ||
xl.ScreenUpdating <- false | ||
let seriesCollection = chart.SeriesCollection() :?> SeriesCollection | ||
for s in seriesCollection do s.Delete() |> ignore | ||
let xs, ys = values xOver, values yOver | ||
for x in xs do | ||
let series = seriesCollection.NewSeries() | ||
series.Name <- (string)x | ||
series.XValues <- ys | ||
series.Values <- ys |> Array.map (f x) | ||
chart.ChartType <- XlChartType.xlSurfaceWireframe | ||
xl.ScreenUpdating <- true | ||
|
||
do | ||
match chart with | ||
| None -> ignore () | ||
| Some(chart) -> redraw () | ||
|
||
member this.Rescale((xmin, xmax), (ymin, ymax)) = | ||
xOver <- (xmin, xmax) | ||
yOver <- (ymin, ymax) | ||
redraw () | ||
|
||
member this.Zoom(zoom: int) = | ||
grain <- zoom | ||
redraw () | ||
|
||
// Create XY scatterplot, colored by group | ||
let scatterplot<'a when 'a: equality> (data: (float * float * 'a ) seq) = | ||
let chart = NewChart () | ||
match chart with | ||
| None -> ignore () | ||
| Some(chart) -> | ||
let xl = chart.Application | ||
xl.ScreenUpdating <- false | ||
let seriesCollection = chart.SeriesCollection() :?> SeriesCollection | ||
let groups = data |> Seq.map (fun (_, _, g) -> g) |> Seq.distinct | ||
for group in groups do | ||
let xs, ys, _ = data |> Seq.filter (fun (_, _, g) -> g = group) |> Seq.toArray |> Array.unzip3 | ||
let series = seriesCollection.NewSeries() | ||
series.Name <- group.ToString() | ||
series.XValues <- xs | ||
series.Values <- ys | ||
chart.ChartType <- XlChartType.xlXYScatter | ||
xl.ScreenUpdating <- true | ||
|
||
// Create XY scatterplot, colored by group, with labels | ||
let labeledplot<'a when 'a: equality> (data: (float * float * 'a * string ) seq) = | ||
let chart = NewChart () | ||
match chart with | ||
| None -> ignore () | ||
| Some(chart) -> | ||
let xl = chart.Application | ||
xl.ScreenUpdating <- false | ||
let seriesCollection = chart.SeriesCollection() :?> SeriesCollection | ||
let groups = data |> Seq.map (fun (_, _, g, _) -> g) |> Seq.distinct | ||
for group in groups do | ||
let filtered = data |> Seq.filter (fun (_, _, g, _) -> g = group) |> Seq.toArray | ||
let xs = filtered |> Array.map (fun (x, _, _, _) -> x) | ||
let ys = filtered |> Array.map (fun (_, y, _, _) -> y) | ||
let ls = filtered |> Array.map (fun (_, _, _, l) -> l) | ||
let series = seriesCollection.NewSeries() | ||
series.Name <- group.ToString() | ||
series.XValues <- xs | ||
series.Values <- ys | ||
series.HasDataLabels <- true | ||
for i in 1 .. filtered.Length do | ||
let point = series.Points(i) :?> Point | ||
point.DataLabel.Text <- ls.[i-1] | ||
chart.ChartType <- XlChartType.xlXYScatter | ||
xl.ScreenUpdating <- true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
## Charting Example | ||
|
||
Update the references in file `ChartingDemo.fsx` and copy the contents of this file into the Excel Hosted Tsunami Shell. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
module StockScript | ||
/// A translation by Matthew Moloney of http://vstostocks.codeplex.com/ by Mathias Brandewinder (Twitter: @brandewinder Blog: http://www.clear-lines.com/blog/) | ||
#r @"C:\Program Files (x86)\Microsoft Visual Studio 11.0\Visual Studio Tools for Office\PIA\Office14\Microsoft.Office.Interop.Excel.dll" | ||
open Microsoft.Office.Interop.Excel | ||
open System | ||
open System.Net | ||
|
||
type TradingDaySummary = {Day : DateTime; Volume : int64; Open : float; Close : float; High : float; Low : float} | ||
|
||
type StockHistory = {Symbol : string; StartDate : DateTime; EndDate : DateTime; History : TradingDaySummary[]} | ||
|
||
let read(symbol : string, startDate : DateTime, endDate : DateTime) : StockHistory = | ||
let query = sprintf "http://ichart.finance.yahoo.com/table.csv?s=%s&a=%i&b=%i&c=%i&d=%i&e=%i&f=%i&g=d&ignore=.csv" | ||
symbol (startDate.Month - 1) startDate.Day startDate.Year (endDate.Month - 1) endDate.Day endDate.Year | ||
|
||
use client = new WebClient() | ||
let history = | ||
let res = client.DownloadString(query) | ||
[| | ||
for line in res.Split([|char 10|]) |> Seq.skip 1 do | ||
match line.Split([|','|]) with | ||
| [|day;``open``;high;low;close;volume; _|] -> | ||
yield {Day = DateTime.Parse(day); Open = float ``open``; High = float high; Low = float low; | ||
Close = float close; Volume = Int64.Parse volume} | ||
| _ -> () | ||
|] | ||
{Symbol = symbol; StartDate = startDate; EndDate = endDate; History = history} | ||
|
||
let run (history : StockHistory, horizon : int, runs : int) = | ||
let closeSeries = history.History |> Array.map (fun x -> x.Close) | ||
let returnsSeries = closeSeries |> Seq.pairwise |> Seq.map (fun (today,tomorrow) -> (tomorrow - today) / today) |> Seq.toArray | ||
let seed = new Random() | ||
let initialValue = 100. | ||
[|0..runs|] | ||
|> Array.map (fun _ -> | ||
let rng = Random(seed.Next()) | ||
/// Simulate | ||
async { | ||
return | ||
[| 0..horizon - 1 |] | ||
|> Array.map (fun _ -> returnsSeries.[rng.Next(returnsSeries.Length)]) | ||
|> Array.fold (fun value ret -> value * (1. + ret)) initialValue | ||
}) | ||
|> Async.Parallel | ||
|> Async.RunSynchronously | ||
|
||
|
||
|
||
|
||
type SeriesData = {Name : string; XValues : obj[]; Values : obj[] } | ||
|
||
let appendSeries (chartType : XlChartType, seriesData : SeriesData) (chart : Chart) = | ||
chart.ChartType <- chartType | ||
let seriesCollection = chart.SeriesCollection() :?> SeriesCollection | ||
let series = seriesCollection.NewSeries() | ||
series.Name <- seriesData.Name | ||
series.Values <- seriesData.Values | ||
series.XValues <- seriesData.XValues | ||
chart | ||
|
||
let addStockHistory (history : StockHistory) (chart : Chart) = | ||
let dataPoints = history.History |> Array.sortBy (fun x -> x.Day) | ||
let xValues = dataPoints |> Array.map (fun x -> box x.Day); | ||
|
||
let close = { | ||
Name = history.Symbol; | ||
XValues = xValues | ||
Values = dataPoints |> Array.map (fun x -> box x.Close) | ||
} | ||
appendSeries (XlChartType.xlLine, close) chart |> ignore | ||
|
||
let addMovingAverages (history : StockHistory) (chart : Chart) = | ||
let dataPoints = history.History |> Array.sortBy (fun x -> x.Day) | ||
let xValues = dataPoints |> Array.map (fun x -> box x.Day); | ||
let movingAverage (day:DateTime) (length:int) = | ||
let xs = | ||
dataPoints | ||
|> Seq.takeWhile (fun x -> x.Day <= day) | ||
|> Seq.toArray | ||
|> Array.rev | ||
|> Array.map (fun x -> x.Close) | ||
|> Seq.truncate length | ||
|> Seq.toArray | ||
if xs.Length = 0 then None else Some((xs |> Array.sum) / float xs.Length) | ||
|
||
|
||
for averages in [|10;50;100|] do | ||
let series = { | ||
Name = sprintf "MA %i days" averages | ||
XValues = xValues | ||
Values = dataPoints |> Array.choose (fun x -> movingAverage x.Day averages |> Option.map box) | ||
} | ||
appendSeries (XlChartType.xlLine, series) chart |> ignore | ||
|
||
|
||
|
||
let addValueDistibution (history : StockHistory, horizon : int, runs : int) (chart : Chart) = | ||
let projections = run (history, horizon, runs) | ||
let min = projections |> Seq.min |> int | ||
let max = projections |> Seq.max |> int | ||
let xValues = [|min..max|] | ||
let values = [|for xValue in xValues -> projections |> Array.filter ((int >> (=) xValue)) |> Array.length |] | ||
let data = | ||
{ | ||
Name = history.Symbol | ||
XValues = xValues |> Array.map box | ||
Values = values |> Array.map box | ||
} | ||
appendSeries (XlChartType.xlColumnStacked, data) chart | ||
|
||
|
||
let writeHistory(history : StockHistory, worksheet : Worksheet) = | ||
let DateColumn = 0 | ||
let OpenColumn = 1 | ||
let CloseColumn = 2 | ||
|
||
let length = history.History.Length | ||
let dataArray = Array2D.init (length + 1) 6 (fun _ _ -> box null) | ||
let formatArray = Array2D.init (length + 1) 6 (fun _ _ -> box null) | ||
|
||
dataArray.[0,DateColumn] <- box "Date" | ||
dataArray.[0,OpenColumn] <- box "Open" | ||
dataArray.[0,CloseColumn] <- box "Close" | ||
|
||
history.History |> Array.iteri (fun i day -> | ||
let line = i + 1 | ||
|
||
dataArray.[line, DateColumn] <- box day.Day | ||
dataArray.[line, OpenColumn] <- box day.Open | ||
dataArray.[line, CloseColumn] <- box day.Close | ||
|
||
formatArray.[line, DateColumn] <- box "YYYY/MM/DD" | ||
formatArray.[line, OpenColumn] <- box "#,##0.00" | ||
formatArray.[line, CloseColumn] <- box "#,##0.00" | ||
) | ||
let range = worksheet.Range(worksheet.Cells.[1,1], worksheet.Cells.[length + 1, 6]) | ||
range.Value2 <- dataArray | ||
range.NumberFormat <- formatArray | ||
|
||
let clear (c:Chart) = | ||
let sc = c.SeriesCollection() :?> Microsoft.Office.Interop.Excel.SeriesCollection | ||
for i in [sc.Count .. -1 .. 1] do sc.Item(i).Delete() |> ignore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters