Loading...
JsQuant
100% Javascript Quant: Trend Following Algorithm Example (
source
)
Symbols
x
$
From
Using
Algorithm...
Add Calculated Columns to Yahoo Finance CSV
/* Algorithm: ----------------------------------------------------------------------------- BUY after All Time High Close SELL after Close below trailing 10 day Average True Range (see calculated Column 12 "Order Action") Format: ----------------------------------------------------------------------------- To calculate additional columns and update/normalize the Yahoo CSV data, a javascript list of two types of functions is used (listed below): // UPDATE COLUMNS EXAMPLE: [{ updateValues: function(allData) { // allData 2d array of rows: [[1,2],[3,4],[1,1], ... ] allData.reverse(); return allData; } }, // ADD COLUMNS EXAMPLE: { // column header "names" are required for new columns, two names indicates two column to be added names: ["some col 1", "some col to add 2"], calculateValues: function(allData) { dojo.forEach(allData, function(row) { row.push(1, 2); // add "1" and "2" as new col values to every row }); return allData; } }] Resultant Data: ----------------------------------------------------------------------------- -- YAHOO FINANCE COLUMNS: 0 Date 1 Open 2 High 3 Low 4 Close 5 Volume 6 Adj Close -- ADDED CALCULATED COLUMNS: 7 Split 8 All Time High Close 9 True Range 10 ATR10 11 Stop At 12 Order Action 13 Bought At 14 Sold At 15 Close % Change 16 Principal 17 Cash 18 Shares 19 Value (Shares and Cash) 20 % Change (Value vs Principal) 21 Trades (Total number of Trades) Actual Functions to Apply Follow: ----------------------------------------------------------------------------- */ [{ // filter incomplete rows, fix types and reverse order updateValues: function(allData) { //console.debug(this, allData[0], allData[allData.length-1]); allData.reverse(); dojo.forEach(allData, function(row) { var dateParts = row[0].split("-"); row[0] = new Date(Number(dateParts[0]), Number(dateParts[1])-1, Number(dateParts[2])); // dojo.date.locale.parse(row[0], {selector: "date", datePattern: "yyyy-MM-dd"}); for (var j=1; j<row.length; j++) row[j] = Number(row[j]); }); //console.debug(this, allData[0], allData[allData.length-1]); return allData; } }, { // COL 7 Split, add and normalize cols 1, 2, 3, 4 names: ["Split"], calculateValues: function(allData) { dojo.forEach(allData, function(row) { var splt = row[6]/row[4]; if (splt != 1) { row[1] = round(row[1] * splt); row[2] = round(row[2] * splt); row[3] = round(row[3] * splt); } row.push(round(splt, 3)); }); return allData; } }, { // COL 8 names: ["All Time High Close"], calculateValues: function(allData) { var allTimeHighClose = 0; dojo.forEach(allData, function(row) { allTimeHighClose = Math.max(allTimeHighClose, row[6]); row.push(allTimeHighClose); }, this); return allData; } }, { // COL 9 names: ["True Range"], calculateValues: function(allData) { var row = []; var prevRow = []; allData[0].push(null); for (var i=1; i<allData.length; i++) { prevRow = allData[i-1]; row = allData[i]; row.push(round(Math.max(row[2], prevRow[6])-Math.min(row[3], prevRow[6]))); } return allData; } }, { // COL 10 names: ["ATR10"], calculateValues: function(allData) { var row = []; var avgTrueRng = null; var rng = 10; for (var i=0; i<allData.length; i++) { row = allData[i]; if (i > rng-2) { sumRng = 0; dojo.forEach(allData.slice(i-rng+1,i), function(r) { sumRng += r[9]; // sum True Range }, this); avgTrueRng = sumRng / rng; } row.push(round(avgTrueRng)); } return allData; } }, { // COL 11 names: ["Stop At"], calculateValues: function(allData) { var stopAt = null; dojo.forEach(allData, function(row) { // if have ATR10 and All Time High if (row[10] && row[6] == row[8]) stopAt = round(row[6]-row[10]); // set Stop At to Adj Close - ATR10 row.push(stopAt); }, this); return allData; } }, { // COL 12 names: ["Order Action"], calculateValues: function(allData) { var row = []; var prevAction = OrderAction.IGNORE; var orderAction = null; allData[0].push(prevAction); for (var i=1; i<allData.length; i++) { row = allData[i]; var adjClose = row[6]; var allTimeHighClose = row[8]; var stopAt = row[11]; if (stopAt && allTimeHighClose == adjClose && prevAction == OrderAction.IGNORE ) { orderAction = OrderAction.BUY; } else if (stopAt && adjClose < stopAt && (prevAction == OrderAction.BUY || prevAction == OrderAction.HOLD) ) { orderAction = OrderAction.SELL; } else if (prevAction == OrderAction.HOLD || prevAction == OrderAction.BUY) { orderAction = OrderAction.HOLD; } else { orderAction = OrderAction.IGNORE; } row.push(orderAction); prevAction = orderAction; } return allData; } }, { // COL 13, 14, 15, 16, 17, 18, 19, 20, 21 names: ["Bought At","Sold At","Close % Change","Principal","Cash","Shares","Value","% Change","Trades"], calculateValues: function(allData) { var closeAt = null; var boughtAt = null; var soldAt = null; var orderAction = null; var principal = Number(dom.byId("principalText").value); var cash = principal; var shares = 0; var value = 0; var tradeCount = 0; dojo.forEach(allData, function(row) { closeAt = row[6]; orderAction = row[12]; if (orderAction == OrderAction.BUY) { boughtAt = closeAt; shares = truncate(cash / boughtAt); cash = round(cash - boughtAt * shares); row.push(boughtAt, null, null); tradeCount += 1; } else if (orderAction == OrderAction.SELL) { soldAt = closeAt; cash = round(cash + soldAt * shares); shares = 0; row.push(boughtAt, soldAt, round((soldAt-boughtAt)/boughtAt*100)); tradeCount += 1; } else { row.push(boughtAt, null, null); } value = round(cash+(shares*closeAt)); row.push(principal, cash, shares, value, round(((value-principal)/principal)*100), // % change tradeCount); }, this); return allData; } }]
Graph Columns
Result Columns
Update
Balance after trading period using algorithm...
Loading...
Tweet
Powered by
Web Services by Yahoo!
Dojo Toolkit
,
Flot Charts
, ©
2013
Alexander Schonfeld