diff --git a/app.js b/app.js
new file mode 100644
index 0000000..fff880a
--- /dev/null
+++ b/app.js
@@ -0,0 +1,47 @@
+var app = angular.module("app", ['ui.router']);
+
+app.config(function($stateProvider, $urlRouterProvider){
+ $urlRouterProvider.otherwise('/index/portfolio');
+
+ $stateProvider.state('index', {
+ url: '/index',
+ views: {
+ 'index': {
+ templateUrl: 'js/templates/index.html',
+ controller: 'MainCtrl'
+ },
+ 'historical': {
+ templateUrl: 'js/templates/historical.html',
+ controller: 'historyCtrl'
+ }
+ }
+ })
+ .state("index.portfolio", {
+ url: '/portfolio',
+ views: {
+ 'display@': {
+ templateUrl: "js/templates/portfolio.html",
+ controller: "portfolioCtrl"
+ }
+ }
+ })
+ .state("index.trade", {
+ url: '/trade/:symbol',
+ views: {
+ 'display@': {
+ templateUrl: "js/templates/trade.html",
+ controller: "tradeCtrl"
+ }
+ }
+ })
+
+ .state("index.transaction", {
+ url: '/transaction',
+ views: {
+ 'display@': {
+ templateUrl: "js/templates/transactions.html",
+ controller: "transactionCtrl"
+ }
+ }
+ })
+})
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..fd61985
--- /dev/null
+++ b/index.html
@@ -0,0 +1,58 @@
+
+
+
+
+ Fideliguard
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/js/controllers/historyController.js b/js/controllers/historyController.js
new file mode 100644
index 0000000..4750a54
--- /dev/null
+++ b/js/controllers/historyController.js
@@ -0,0 +1,70 @@
+app.controller("historyCtrl", ['$scope', '$filter', 'historicalStock', 'selectedDate', function($scope, $filter, historicalStock, selectedDate){
+ $scope.stockData = historicalStock.getStockData();
+
+ $scope.sortCriteria = "";
+ $scope.reverse = false;
+
+ $scope.sortBy = function(criteria){
+ var columns = {
+ 1: "Symbol",
+ 2: "Close",
+ 3: $scope.getYesterday,
+ 4: $scope.getLastMonth,
+ 5: $scope.getLast6Month,
+ }
+ if (!columns[criteria]) return;
+
+ if (columns[criteria] == $scope.sortCriteria){
+ $scope.reverse = !$scope.reverse;
+ } else {
+ $scope.sortCriteria = columns[criteria];
+ }
+ }
+
+
+
+ $scope.symbols = function() {
+ return $scope.stockData.reduce(function(result, current){
+ if (result.indexOf(current.Symbol) == -1) {
+ result.push(current.Symbol);
+ }
+ return result;
+ }, [])
+ }
+
+ $scope.selectedDate = selectedDate.getDate;
+
+ $scope.getLast = function(offset, entry){
+ var currentClosing = entry.Close;
+ var startingDate = new Date(entry.Date);
+ var targetDays = [];
+ targetDays.push(startingDate.setDate(startingDate.getDate() - offset))
+ targetDays.push(startingDate.setDate(startingDate.getDate() - 1))
+ targetDays.push(startingDate.setDate(startingDate.getDate() - 1))
+ targetDays.push(startingDate.setDate(startingDate.getDate() - 1))
+ targetDays.push(startingDate.setDate(startingDate.getDate() - 1))
+
+ var filteredData = $scope.stockData.filter(function(el){ return el.Symbol == entry.Symbol })
+ var results = [];
+ targetDays.forEach(function(day) {
+ var result = $filter("dateFilter")(filteredData, day);
+ if (result.length > 0 && results.length == 0) {
+ results = result;
+ }
+ });
+
+ return (results.length < 1) ? "N/A" : currentClosing - results[0].Close
+ }
+
+ $scope.getYesterday = function(entry){
+ return $scope.getLast(0, entry);
+ }
+
+ $scope.getLastMonth = function(entry){
+ return $scope.getLast(29, entry);
+ }
+
+ $scope.getLast6Month = function(entry){
+ return $scope.getLast(179, entry);
+ }
+}]);
diff --git a/js/controllers/mainController.js b/js/controllers/mainController.js
new file mode 100644
index 0000000..d44d34a
--- /dev/null
+++ b/js/controllers/mainController.js
@@ -0,0 +1,7 @@
+app.controller("MainCtrl", ['$scope', 'selectedDate', function($scope, selectedDate){
+ $scope.selectedDate = selectedDate.getDate;
+ $scope.currentDate = "";
+ $scope.$watch("currentDate", function(){
+ selectedDate.setDate($scope.currentDate);
+ })
+}]);
diff --git a/js/controllers/portfolioController.js b/js/controllers/portfolioController.js
new file mode 100644
index 0000000..ba0a672
--- /dev/null
+++ b/js/controllers/portfolioController.js
@@ -0,0 +1,61 @@
+app.controller("portfolioCtrl", ['$scope',
+ 'transactionService',
+ 'historicalStock',
+ 'selectedDate',
+ function($scope, transactionService, historicalStock, selectedDate){
+ $scope.currentDate = selectedDate.getDate;
+ $scope.portfolio = transactionService.portfolio(selectedDate.getDate())
+ $scope.money = transactionService.getMoney($scope.currentDate())
+
+ $scope.getPrice = historicalStock.getPrice;
+ $scope.yesterday = historicalStock.getYesterday;
+ $scope.lastMonth = historicalStock.getLastMonth;
+ $scope.last6 = historicalStock.getLast6Month;
+
+ $scope.portfolioPrevious = function(offset){
+ var now = new Date($scope.currentDate())
+ now = new Date(now.setDate(now.getDate() - offset));
+
+ console.log(now);
+ if (now < Date.parse('1/1/2014')) return "N/A"
+
+ var previousPortfolio = transactionService.portfolio(now);
+
+ return transactionService.getMoney(now) + previousPortfolio.reduce(function(total, el){
+ total += historicalStock.getPrice(now, el.symbol) * el.quantity;
+ return total;
+ }, 0)
+ }
+
+ $scope.portfolioYesterday = function(){
+ return $scope.portfolioPrevious(1);
+
+ }
+
+ $scope.portfolioLastMonth = function(){
+ return $scope.portfolioPrevious(30);
+ }
+
+ $scope.portfolioLast6Month = function(){
+ return $scope.portfolioPrevious(180);
+ }
+
+ $scope.stockValue = function(){
+ return $scope.portfolio.reduce(function(total, el){
+ total += historicalStock.getPrice($scope.currentDate(), el.symbol) * el.quantity;
+ return total;
+ }, 0)
+ }
+
+ $scope.totalCost = function(){
+ return $scope.portfolio.reduce(function(total, el){
+ total += el.cost
+ return total;
+ }, 0)
+ }
+
+ $scope.$watch('currentDate()', function(){
+ $scope.portfolio = transactionService.portfolio($scope.currentDate());
+ $scope.money = transactionService.getMoney($scope.currentDate())
+ });
+}]);
diff --git a/js/controllers/tradeController.js b/js/controllers/tradeController.js
new file mode 100644
index 0000000..96c7011
--- /dev/null
+++ b/js/controllers/tradeController.js
@@ -0,0 +1,43 @@
+app.controller("tradeCtrl", ['$scope', '$stateParams', 'selectedDate', 'historicalStock', 'transactionService',
+ function($scope, $stateParams, selectedDate, historicalStock, transactionService){
+ $scope.tradeData = {};
+ $scope.currentMoney = transactionService.getMoney;
+ $scope.tradeData.symbol = $stateParams.symbol;
+ $scope.tradeData.date = selectedDate.getDate;
+
+ $scope.displayMoney = function(){
+ return $scope.currentMoney($scope.tradeData.date());
+ }
+
+ $scope.futureMoney = function(){
+ return transactionService.getFutureMoney();
+ }
+
+ $scope.calcCost = function(){
+ return $scope.calcPrice() * Number($scope.tradeData.quantity);
+ }
+
+ $scope.calcPrice = function(){
+ return historicalStock.getPrice(selectedDate.getDate(), $scope.tradeData.symbol);
+ }
+
+ $scope.createTranscation = function() {
+ var tradeRecord = JSON.parse(JSON.stringify($scope.tradeData));
+ tradeRecord.action = $scope.tradeData.action == "true" ? true : false
+ tradeRecord.date = $scope.tradeData.date();
+ tradeRecord.cost = Number($scope.calcCost());
+ tradeRecord.price = Number($scope.calcPrice());
+ tradeRecord.quantity = Number(tradeRecord.quantity);
+ transactionService.addTransaction(tradeRecord);
+ }
+
+ $scope.validBuy = function() {
+ return $scope.tradeData.action == "true" && transactionService.validateBuy($scope.tradeData.date(), $scope.calcCost());
+ }
+
+ $scope.validSell = function() {
+ return $scope.tradeData.action != "true" && transactionService.validateSale($scope.tradeData.symbol,
+ $scope.tradeData.date(),
+ $scope.tradeData.quantity);
+ }
+}]);
diff --git a/js/controllers/transactionController.js b/js/controllers/transactionController.js
new file mode 100644
index 0000000..2d00a4c
--- /dev/null
+++ b/js/controllers/transactionController.js
@@ -0,0 +1,24 @@
+app.controller("transactionCtrl", ['$scope', 'transactionService', function($scope, transactionService){
+ $scope.transactions = transactionService.transactions;
+
+ $scope.sortCriteria = "";
+ $scope.reverse = false;
+
+ $scope.sortBy = function(criteria){
+ var columns = {
+ 1: "date",
+ 2: "symbol",
+ 3: "action",
+ 4: "quantity",
+ 5: "price"
+ }
+ if (!columns[criteria]) return;
+
+ if (columns[criteria] == $scope.sortCriteria){
+ $scope.reverse = !$scope.reverse;
+ } else {
+ $scope.sortCriteria = columns[criteria];
+ $scope.reverse = false;
+ }
+ }
+}]);
diff --git a/js/directives/stateDropdown.html b/js/directives/stateDropdown.html
new file mode 100644
index 0000000..13e2600
--- /dev/null
+++ b/js/directives/stateDropdown.html
@@ -0,0 +1,11 @@
+
+
+
+
\ No newline at end of file
diff --git a/js/directives/stateDropdown.js b/js/directives/stateDropdown.js
new file mode 100644
index 0000000..c6fc290
--- /dev/null
+++ b/js/directives/stateDropdown.js
@@ -0,0 +1,7 @@
+app.directive("stateDropdown", function(){
+ return {
+ templateUrl: "js/directives/stateDropdown.html",
+ restrict: "E",
+ scope: {}
+ }
+})
\ No newline at end of file
diff --git a/js/filters/dateFilter.js b/js/filters/dateFilter.js
new file mode 100644
index 0000000..cef64ea
--- /dev/null
+++ b/js/filters/dateFilter.js
@@ -0,0 +1,39 @@
+app.filter("dateFilter", function(){
+ return function(collection, date){
+ return collection.filter(function(el) {
+ var chosenDate = new Date(el.Date)
+ targetDate = new Date(date)
+ chosenDate.setHours(0,0,0,0);
+ targetDate.setHours(0,0,0,0);
+ targetDate.setDate(targetDate.getDate() - 1);
+ return (chosenDate <= targetDate && chosenDate >= targetDate);
+ });
+ };
+});
+
+app.filter("beforeDateFilter", function(){
+ return function(collection, date){
+ return collection.filter(function(el) {
+ var chosenDate = new Date(el.date)
+ targetDate = new Date(date)
+ chosenDate.setHours(0,0,0,0);
+ targetDate.setHours(0,0,0,0);
+ targetDate.setDate(targetDate.getDate() - 1);
+ return (chosenDate <= targetDate);
+ });
+ };
+});
+
+app.filter("afterDateFilter", function(){
+ return function(collection, date){
+ return collection.filter(function(el) {
+ var chosenDate = new Date(el.date)
+ targetDate = new Date(date)
+ chosenDate.setHours(0,0,0,0);
+ targetDate.setHours(0,0,0,0);
+ targetDate.setDate(targetDate.getDate() - 1);
+ return !(chosenDate <= targetDate);
+ });
+ };
+});
+
diff --git a/js/filters/tableFilter.js b/js/filters/tableFilter.js
new file mode 100644
index 0000000..63fb3dc
--- /dev/null
+++ b/js/filters/tableFilter.js
@@ -0,0 +1,19 @@
+app.filter('tableFilter', function(orderByFilter){
+ return function(collection, expression, reverse){
+ if (typeof expression == 'string') {
+ if ( expression == "Close") {
+ var result = collection.sort(function(a, b){
+ return Number(a.Close) - Number(b.Close);
+ });
+ return reverse ? result.reverse() : result;
+ } else {
+ return orderByFilter(collection, expression, reverse)
+ }
+ } else {
+ var result = collection.sort(function(a, b){
+ return expression(a) - expression(b);
+ })
+ return reverse ? result.reverse() : result;
+ }
+ }
+})
\ No newline at end of file
diff --git a/js/services/historicalStock.js b/js/services/historicalStock.js
new file mode 100644
index 0000000..0bf5909
--- /dev/null
+++ b/js/services/historicalStock.js
@@ -0,0 +1,70 @@
+app.factory('historicalStock', ['$http', '$filter', function($http, $filter){
+ var _symbols = ["AAPL", "GOOG", "MSFT", "FB", "YHOO", "NFLX"];
+ var stockData = [];
+
+ _symbols.forEach(function(sym) {
+ _getSymData(sym, function(result){
+ stockData.push.apply(stockData, result.data.query.results.quote)
+ });
+ })
+
+ function getStockData() {
+ return stockData;
+ }
+
+ function getPrice(date, symbol){
+ var target = $filter("dateFilter")(stockData, date).filter(function(el){ return el.Symbol == symbol })[0];
+ return target ? target.Close : null;
+ }
+
+ function _getSymData(sym, callback) {
+ var url = 'http://query.yahooapis.com/v1/public/yql?q=%20select%20*%20from%20yahoo.finance.historicaldata%20where%20symbol%20=%20%22' + sym + '%22%20and%20startDate%20=%20%222014-01-01%22%20and%20endDate%20=%20%222014-12-31%22%20&format=json%20&diagnostics=true%20&env=store://datatables.org/alltableswithkeys%20&callback='
+ return $http.get(url)
+ .then(callback)
+ }
+
+ function getLast(offset, date, symbol){
+ var currentClosing = getPrice(date, symbol);
+ var startingDate = new Date(date);
+ var targetDays = [];
+ targetDays.push(startingDate.setDate(startingDate.getDate() - offset - 1))
+ targetDays.push(startingDate.setDate(startingDate.getDate() - 1))
+ targetDays.push(startingDate.setDate(startingDate.getDate() - 1))
+ targetDays.push(startingDate.setDate(startingDate.getDate() - 1))
+ targetDays.push(startingDate.setDate(startingDate.getDate() - 1))
+
+
+ var filteredData = stockData.filter(function(el){ return el.Symbol == symbol })
+ var results = [];
+ targetDays.forEach(function(day) {
+ var result = $filter("dateFilter")(filteredData, day);
+ if (result.length > 0 && results.length == 0) {
+ results = result;
+ }
+ });
+
+ if (!currentClosing) return "N/A"
+
+ return (results.length < 1) ? "N/A" : currentClosing - results[0].Close
+ }
+
+ function getYesterday(date, symbol){
+ return getLast(0, date, symbol);
+ }
+
+ function getLastMonth(date, symbol){
+ return getLast(29, date, symbol);
+ }
+
+ function getLast6Month(date, symbol){
+ return getLast(179, date, symbol);
+ }
+
+ return {
+ getPrice: getPrice,
+ getStockData: getStockData,
+ getYesterday: getYesterday,
+ getLastMonth: getLastMonth,
+ getLast6Month: getLast6Month,
+ }
+}]);
diff --git a/js/services/selectedDate.js b/js/services/selectedDate.js
new file mode 100644
index 0000000..650d225
--- /dev/null
+++ b/js/services/selectedDate.js
@@ -0,0 +1,19 @@
+app.factory('selectedDate', function(){
+ var _currentDate;
+
+ function getDate() {
+ return _currentDate;
+ };
+
+ function setDate(offset) {
+ var baseDate = new Date('01/01/2014');
+ var startDate = new Date(baseDate);
+ startDate.setDate(startDate.getDate()+Number(offset));
+ _currentDate = startDate;
+ };
+
+ return {
+ getDate: getDate,
+ setDate: setDate
+ }
+})
diff --git a/js/services/transactionService.js b/js/services/transactionService.js
new file mode 100644
index 0000000..6314ebc
--- /dev/null
+++ b/js/services/transactionService.js
@@ -0,0 +1,171 @@
+app.factory('transactionService', ["$filter", function($filter){
+ var transactions = [
+ {
+ action: true,
+ cost: 5318.20023,
+ date: new Date('Fri Apr 04 2014 00:00:00 GMT-0500 (CDT)'),
+ price: 531.820023,
+ quantity: 10,
+ symbol: "AAPL"
+ },
+ {
+ action: true,
+ cost: 44.95,
+ date: new Date('Fri Aug 20 2014 00:00:00 GMT-0500 (CDT)'),
+ price: 44.95,
+ quantity: 1,
+ symbol: "MSFT",
+ },
+ {
+ action: true,
+ cost: 67835.727417,
+ date: new Date('Jan 23 2014 00:00:00 GMT-0500 (CDT)'),
+ price: 551.509979,
+ quantity: 123,
+ symbol: "AAPL",
+ },
+ {
+ action: false,
+ cost: 66964.887171,
+ date: new Date('Feb 22 2014 00:00:00 GMT-0500 (CDT)'),
+ price: 544.429977,
+ quantity: 123,
+ symbol: "AAPL",
+ }
+ ]
+
+ // Day bought
+ // Symbol
+ // Total amount bought
+
+ // For the portfolio, the quantity of held shares and the cost
+ // basis for a given symbol are required from this service.
+
+
+ function addTransaction(tradeData){
+ transactions.push(tradeData);
+ }
+
+ function getMoney(date){
+ var startingMoney = 100000;
+ var spentMoney = calculateSpentMoney(date);
+ var profits = calculateProfits(date);
+
+ return startingMoney - spentMoney + profits;
+ }
+
+ function getFutureMoney(){
+ return getMoney(new Date('12/31/2014'))
+ }
+
+ function calculateSpentMoney(date){
+ return $filter("beforeDateFilter")(transactions, date).filter(function (el){
+ return el.action
+ }).reduce(function (total, el){
+ return total += el.cost;
+ }, 0)
+ }
+
+ function calculateProfits(date){
+ return $filter("beforeDateFilter")(transactions, date).filter(function (el){
+ return !el.action
+ }).reduce(function (total, el){
+ return total += el.cost;
+ }, 0)
+ }
+
+ // To make a purchase you both need sufficient money,
+ // and this purchase cannot cause a future purchase to put you in the red.
+ function validateBuy(date, cost){
+ // Calculate how much money we'd have at the given date if we bought
+ var currentMoney = getMoney(date) - cost;
+
+ // If we have insufficient funds right now, return false.
+ if (currentMoney < 0) return false;
+
+ // Get a list of all transactions that happen on/after this date.
+ // Sort them by date.
+ var futureTransactions = $filter("afterDateFilter")(transactions, date).sort(function(a, b){
+ return new Date(a.date) - new Date(b.date);
+ });
+
+ // Return whether every transaction applied in order never puts us in red.
+ return futureTransactions.every(function (el){
+ currentMoney += el.action ? -el.cost : el.cost
+ return (currentMoney >= 0);
+ })
+ }
+
+ // Perform the same validation as buying but checking the integrity
+ // of the share count instead.
+ function validateSale(symbol, date, quantity){
+ var currentShares = countShares(symbol, date) - quantity;
+
+ if (currentShares < 0 || isNaN(quantity)) return false;
+
+ var futureTransactions = $filter("afterDateFilter")(transactions, date).sort(function(a, b){
+ return new Date(a.date) - new Date(b.date);
+ });
+
+ return futureTransactions.every(function (el){
+ currentShares += el.action ? el.quantity : -el.quantity
+ return (currentShares >= 0);
+ })
+ }
+
+ // Finds the first sale of a given symbol on/after the given date.
+ function countFutureShares(symbol){
+ return countShares(symbol, new Date('12/31/2014'))
+ }
+
+ // Calculates the value of shares held using transactions before/on
+ // given date.
+ function countShares(symbol, date) {
+ return $filter("beforeDateFilter")(transactions, date)
+ .reduce(function(total, ele){
+ if (ele.symbol == symbol && ele.action) {
+ total += ele.quantity;
+ } else if (ele.symbol == symbol) {
+ total -= ele.quantity;
+ }
+ return total;
+ }, 0)
+ }
+
+ function portfolio(date) {
+ var portfolio = $filter("beforeDateFilter")(transactions, date).reduce(function (result, el){
+ if (!result[el.symbol]) result[el.symbol] = { quantity: 0, cost: 0.00};
+ if (el.action){
+ result[el.symbol].quantity += el.quantity;
+ result[el.symbol].cost -= el.cost;
+ } else {
+ result[el.symbol].quantity -= el.quantity;
+ result[el.symbol].cost += el.cost;
+ }
+ return result;
+ }, {})
+
+ var filteredPortfolio = [];
+
+ for (symbol in portfolio){
+ // if (portfolio[symbol].quantity > 0){
+ var portfolioRow = portfolio[symbol]
+ portfolioRow.symbol = symbol;
+ filteredPortfolio.push(portfolioRow)
+ // }
+ }
+
+ return filteredPortfolio;
+ }
+
+ return {
+ getMoney: getMoney,
+ getFutureMoney: getFutureMoney,
+ transactions: transactions,
+ addTransaction: addTransaction,
+ validateSale: validateSale,
+ validateBuy: validateBuy,
+ portfolio: portfolio,
+ }
+
+}]);
diff --git a/js/templates/historical.html b/js/templates/historical.html
new file mode 100644
index 0000000..28e4762
--- /dev/null
+++ b/js/templates/historical.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+ | Symbol |
+ Price |
+ 1d |
+ 30d |
+ 6month |
+ Trade? |
+
+
+
+ | {{ dataRow.Symbol }} |
+ {{ dataRow.Close | currency }} |
+ {{ getYesterday(dataRow) | currency }} |
+ {{ getLastMonth(dataRow) | currency }} |
+ {{ getLast6Month(dataRow) | currency }} |
+ trade |
+
+
+
+
+
diff --git a/js/templates/index.html b/js/templates/index.html
new file mode 100644
index 0000000..ef4d965
--- /dev/null
+++ b/js/templates/index.html
@@ -0,0 +1,6 @@
+
+
+ 1/1/2014 12/31/2014
+ {{ selectedDate() | date }}
+
+
diff --git a/js/templates/portfolio.html b/js/templates/portfolio.html
new file mode 100644
index 0000000..5a00c99
--- /dev/null
+++ b/js/templates/portfolio.html
@@ -0,0 +1,58 @@
+
+
+
+
+
+ | Cost Basis |
+ Current Value |
+ Profit |
+ 1d |
+ 30d |
+ 6month |
+
+
+ | {{ money - totalCost() | currency }} |
+ {{ money + stockValue() | currency }} |
+ {{ stockValue() + totalCost() | currency }} |
+ {{ money + stockValue() - portfolioYesterday() | currency }} |
+ {{ money + stockValue() - portfolioLastMonth() | currency }} |
+ {{ money + stockValue() - portfolioLast6Month() | currency }} |
+
+
+
+
+ | Symbol |
+ Quantity |
+ Cost Basis |
+ Current Value |
+ Profits |
+ Current Price |
+ Trade? |
+
+
+
+ | Cash |
+ {{ money | currency }} |
+ {{ money | currency }} |
+ {{ money | currency }} |
+ |
+ |
+ |
+
+
+ | {{ row.symbol }} |
+ {{ row.quantity }} |
+ {{ row.cost | currency }} |
+ {{ row.quantity * getPrice(currentDate(), row.symbol) | currency }} |
+ {{ row.quantity * getPrice(currentDate(), row.symbol) + row.cost | currency }} |
+ {{ getPrice(currentDate(), row.symbol) | currency }} |
+ trade |
+
+
+
+
+
+
+
diff --git a/js/templates/trade.html b/js/templates/trade.html
new file mode 100644
index 0000000..dd0363e
--- /dev/null
+++ b/js/templates/trade.html
@@ -0,0 +1,42 @@
+
diff --git a/js/templates/transactions.html b/js/templates/transactions.html
new file mode 100644
index 0000000..893eca8
--- /dev/null
+++ b/js/templates/transactions.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+ | Date |
+ Symbol |
+ Type |
+ Quantity |
+ Price |
+
+
+
+ | {{ transaction.date | date }} |
+ {{ transaction.symbol }} |
+ {{ transaction.action ? "Buy" : "Sell" }} |
+ {{ transaction.quantity }} |
+ {{ transaction.price }} |
+
+
+
+
+
+Sorting By: {{ sortCriteria? sortCriteria : "Nothing" }}, Descending {{ reverse }}
+
+