Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AAPL.json

Large diffs are not rendered by default.

59 changes: 59 additions & 0 deletions Notes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
_stocks:
{
AAPL: {
2015-01-02: {
Close:
},
2015-01-05: {
Close:
}
...
},

AREX: {

}
...
}


_dates:
{
2015-01-02: [AAPL, AREX, ...],
2015-01-05: [],
...
}

_dateCollection:
["2015-01-02", "2015-01-05", ...]

_stockDates:
{
AAPL: {
0: "2015-01-02",
1: "2015-01-05",
...
},
AREX:{}
...
}

portfolio:
{
AAPL: {
quantity: 1400,
moneySpent:,
moneyEarned:

}
}

transactions:
[{
date: ,
symbol: ,
type: ,
quantity: ,
price:

}]
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# assignment_fideligard_spa
Buy low, sell high.
Deployed version [here](http://fideligard.surge.sh/)

[An AngularJS JavaScript single-page web application using services, directives, ui-router, and good modular code to create a stock portfolio simulator using Yahoo's finance trading data](http://www.vikingcodeschool.com)
Fideligard allows clients to test the historical performance of stock portfolios. Buy and sell stocks based on past performance and Fidelagard will keep track of your transactions and portfolio at any given date. Fideligard is an Angular JS Javascript single-page web application using services, direcrives, ui-router and multi-view states. Historical data comes from Yahoo Finance.

Fideligard also includes a stock-trading game. Start on day 1 and make trades one day at a time. The goal is to have the best-performing portfolio at the end of the simulation.

![Trading view](screenshots/trade_screen.png "Trading view. Choose from stocks on ticker on the left and change the date using the slider.")
91 changes: 91 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<!DOCTYPE html>
<html ng-app="stocks">
<head>
<title>Fideligard</title>

<!--Angular-->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.1/angular-ui-router.js"></script>

<!--Lo-Dash -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.1/lodash.js"></script>

<!-- font awesome -->
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-T8Gy5hrqNKT+hzMclPo118YTQO6cYprQmhrYwIiQ/3axmI1hQomh7Ud2hPOy8SP1" crossorigin="anonymous">

<!--Loading Bar-->
<script src="js/vendor/pace.min.js"></script>
<link rel="stylesheet" href="js/vendor/loadingbar.css">

<!--my styles-->
<link rel="stylesheet" href="styles.css">

<!-- Bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</head>
<body>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#"><span class="glyphicon glyphicon-home"></span>&nbspFideligard Historical Portfolio Simulator</a>
</div>
</div><!-- /.container-fluid -->
</nav>

<div class="btn-group" role="group">
<button ui-sref="main.game" ng-show="{{currentPath===''}}">Game</button>
<button ui-sref="main.portfolio" ng-show="{{currentPath===''}}">Just Explore</button>
</div>

<div class="container">
<div class="row">
<div class="col-md-4">
<div ui-view="stocksTicker"></div>
</div>
<div class="col-md-7 col-md-offset-1">
<div class="row">
<div ui-view="dateSlider"></div>
</div>
<div class="row">
<div ui-view="mainContent"></div>
</div>
</div>
</div>
</div>

<script src="js/app.js"></script>
<!--Services-->
<script src="js/services/dateService.js"></script>
<script src="js/services/stocksService.js"></script>
<script src="js/services/accountService.js"></script>
<script src="js/services/mainService.js"></script>
<!--Controllers-->
<script src="js/controllers/dateCtrl.js"></script>
<script src="js/controllers/stocksCtrl.js"></script>
<script src="js/controllers/tradeCtrl.js"></script>
<script src="js/controllers/transactionsCtrl.js"></script>
<script src="js/controllers/portfolioCtrl.js"></script>
<script src="js/controllers/gameDateCtrl.js"></script>
<script src="js/controllers/introCtrl.js"></script>
<!--Directives-->
<script src="js/directives/stockTicker.js"></script>
<script src="js/directives/tradeForm.js"></script>
<script src="js/directives/portfolioRow.js"></script>
<!--Filters-->
<script src="js/filters/filters.js"></script>

</body>
</html>
77 changes: 77 additions & 0 deletions js/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"use strict";
var app = angular.module('stocks', ['ui.router']);

//lodash
app.factory('_', ['$window', function($window){
return $window._;
}]);

app.run(function($rootScope){
$rootScope.$on("$stateChangeError", console.log.bind(console));
});

//routes
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider){

$urlRouterProvider.otherwise('/fideligard');

$stateProvider
.state('main', {
url: '/fideligard',
views: {
'stocksTicker':{
templateUrl: 'js/templates/stocksTicker.html',
controller: "StocksCtrl"
},
'dateSlider':{
templateUrl: 'js/templates/introOptions.html',
controller: 'IntroCtrl'
},
'mainContent':{
templateUrl: 'js/templates/portfolio.html',
controller: 'PortfolioCtrl'
}
},
resolve: {
date: function(dateService) {
return dateService.getDate();
},
stocks: function(StocksService){
return StocksService.all();
},
dates: ['stocks', 'StocksService', function(stocks, StocksService){
return StocksService.getDateCollection();
}]
}
})
.state('main.portfolio', {
url: '/portfolio',
views:{
'dateSlider@': {
templateUrl: 'js/templates/dateSlider.html',
controller: "DateCtrl"
}
}
})
.state('main.portfolio.trade', {
url: '/trade',
params: {symbol: ''},
views: {
'mainContent@':{
templateUrl: 'js/templates/trade.html',
controller: 'TradeCtrl'
}
}

})
.state('main.portfolio.transactions', {
url: '/transactions',
views: {
'mainContent@': {
templateUrl: 'js/templates/transactions.html',
controller: 'TransactionsCtrl'
}
}
});

}]);
36 changes: 36 additions & 0 deletions js/controllers/dateCtrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use strict";
app.controller('DateCtrl', ["$scope", 'date', 'dateService', 'dates', 'mainService', function($scope, date, dateService, dates, mainService) {

$scope.state = mainService.getState();
$scope.selectedDate = date;

$scope.editing = false;

$scope.newDate = date.index;
$scope.dates = dates;

$scope.setDate = function(day) {
dateService.setDay(day);
};

$scope.changeDate = function(date){
var stringDate = date.toISOString().substring(0,10);
var dayOfYear = $scope.dates.indexOf(stringDate);
if(dayOfYear >= 0){
dateService.setDay(dayOfYear);
$scope.newDate = dayOfYear;
}
$scope.editing = !$scope.editing;
};

$scope.nextDay = function(){
dateService.nextDay();
};

$scope.currentDate = function(){
return dates[$scope.selectedDate.index];
};

//make it more obvious that you can click on the date to change it

}]);
32 changes: 32 additions & 0 deletions js/controllers/gameDateCtrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use strict";
app.controller('GameDateCtrl', ["$scope", 'date', 'dateService', 'dates', function($scope, date, dateService, dates) {

$scope.editing = false;
$scope.selectedDate = date;
$scope.newDate = date.index;
$scope.dates = dates;

$scope.setDate = function(day) {
dateService.setDay(day);
};

$scope.changeDate = function(date){
var stringDate = date.toISOString().substring(0,10);
var dayOfYear = $scope.dates.indexOf(stringDate);
if(dayOfYear >= 0){
dateService.setDay(dayOfYear);
$scope.newDate = dayOfYear;
}
$scope.editing = !$scope.editing;
};

$scope.nextDay = function(){
dateService.nextDay();
};

$scope.currentDate = function(){
return dates[$scope.selectedDate.index];
};
//make it more obvious that you can click on the date to change it

}]);
6 changes: 6 additions & 0 deletions js/controllers/introCtrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"use strict";
app.controller("IntroCtrl", ['$scope', 'mainService', function($scope, mainService){
$scope.changeState = function(state){
mainService.setState(state);
};
}]);
15 changes: 15 additions & 0 deletions js/controllers/portfolioCtrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use strict";
app.controller('PortfolioCtrl', ['$scope', 'accountService', 'date', 'dates', 'dateService', function($scope, accountService, date, dates, dateService){
$scope.account = accountService.getBalance();
console.log($scope.account);
$scope.transactions = accountService.getTransactions();
//set a watch on the date and build portfolio whenever it changes
//will need to pass in the new date.index
$scope.currentDate = dateService.getDate();
accountService.buildPortfolio($scope.currentDate, dates);
$scope.portfolio = accountService.getPortfolio();
$scope.statistics = accountService.getPortfolioStats();
$scope.$watch('currentDate.index', function(){
accountService.buildPortfolio($scope.currentDate, dates);
});
}]);
16 changes: 16 additions & 0 deletions js/controllers/stocksCtrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use strict";

app.controller('StocksCtrl', ["$scope", 'date', 'stocks', 'dates', function($scope, date, stocks, dates){

$scope.selectedDate = date;
$scope.stocks = stocks;
$scope.dates = dates;

$scope.sortBy = "symbol";
$scope.sortTable = function(property){
if(property == "symbol"){
return "-symbol";
}
};

}]);
6 changes: 6 additions & 0 deletions js/controllers/tradeCtrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"use strict";
app.controller('TradeCtrl', ['$scope', 'dates', '$stateParams', function($scope, dates, $stateParams){

$scope.symbol = $stateParams.symbol || "AAPL";
$scope.dates = dates;
}]);
9 changes: 9 additions & 0 deletions js/controllers/transactionsCtrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"use strict";
app.controller('TransactionsCtrl', ['$scope', 'accountService', function($scope, accountService){

$scope.transactions = accountService.getTransactions();

$scope.sortType = 'date';
$scope.sortReverse = false;

}]);
21 changes: 21 additions & 0 deletions js/directives/portfolioRow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"use strict";
app.directive('portfolioRow', ['StocksService', 'accountService', function(StocksService, accountService){
return{
restrict: "A",
templateUrl: "js/templates/portfolioRow.html",
scope: {
stock: "=",
symbol: "="
},
link: function(scope){
scope.currentPrice = StocksService.currentPrice(scope.symbol);
scope.currentValue = scope.stock.quantity * scope.currentPrice;
scope.costBasis = scope.stock.moneySpent - scope.stock.moneyEarned;
scope.profitLoss = scope.currentValue - scope.costBasis;
scope.thirtyDay = StocksService.priceChange(scope.symbol, 30);
scope.sevenDay = StocksService.priceChange(scope.symbol, 7);
scope.oneDay = StocksService.priceChange(scope.symbol, 1);
}
};

}]);
Loading