Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
ad22c51
start date widget
eating247 Mar 18, 2017
1bdfcc2
save date
eating247 Mar 18, 2017
a271f98
hard coded stock panel
eating247 Mar 18, 2017
919c5e7
update README
eating247 Apr 26, 2017
a7c4dab
add personal website link
eating247 Apr 26, 2017
4874f86
fix typo
eating247 Apr 26, 2017
5d1d8a3
comment + review date form
eating247 Apr 27, 2017
c0e1321
Refactor date change event
eating247 Apr 27, 2017
891da17
Switch back to vanilla js
eating247 Apr 27, 2017
8123f43
make tables responsive
eating247 Apr 27, 2017
d22b98c
configure yahoo finance api calls
eating247 May 11, 2017
59a7ee1
reposition nav
eating247 May 11, 2017
e73544b
resolve async calls
eating247 May 11, 2017
7686ca1
filter stocks by date
eating247 May 11, 2017
7bd6a49
reformat data for table
eating247 May 11, 2017
c98cb73
update year
eating247 May 11, 2017
9b933cb
calculate changes in prices from 1, 7, and 30 days ago
eating247 May 11, 2017
320977e
comments for date service
eating247 May 11, 2017
30cb17d
refactor stock service
eating247 May 11, 2017
2b42ff7
display stock data in table
eating247 May 11, 2017
5eff709
clip whitespace from stock symbol
eating247 May 11, 2017
52ee2e8
add flash message
eating247 May 11, 2017
327fa92
clean up holes in stock data
eating247 May 12, 2017
9a0cdcd
multi-view states, data still dirty
eating247 May 13, 2017
dc39271
links between multi-view states working
eating247 May 13, 2017
f803f07
add trade form
eating247 May 13, 2017
c5af01c
finish trade template view
eating247 May 13, 2017
06c35df
add some funcionality to trade form
eating247 May 13, 2017
f274336
make trade form more dynamic
eating247 May 13, 2017
63d685e
pass date and price params (symbol params not working)
eating247 May 13, 2017
6e5d867
pass symbol params through ui-sref
eating247 May 13, 2017
bdc1118
autopopulate trade form from stocks panel
eating247 May 13, 2017
79b8d65
eliminate unnecessary inputs on trade form
eating247 May 13, 2017
56dc9b9
build transactions view
eating247 May 13, 2017
626350b
dynamically calculating cost in form
eating247 May 13, 2017
fe5dcbc
displaying order status
eating247 May 13, 2017
8c3eb5a
fix cost and order status to update from controller
eating247 May 13, 2017
b9e7842
disable form submission if invalid
eating247 May 13, 2017
cf0f84a
store trades in trade service
eating247 May 13, 2017
291ab0d
redirect after recording trade
eating247 May 13, 2017
f7b3c92
populate transactions in table
eating247 May 13, 2017
54f2879
display type for transactions
eating247 May 13, 2017
07ca5d8
sort stocks table by ticker
eating247 May 13, 2017
a45fe0a
styling to ticker filter
eating247 May 13, 2017
bf34cd5
sorting for transactions
eating247 May 13, 2017
6a7c1c1
add styling for transaction sorting
eating247 May 13, 2017
b1880a4
format currency
eating247 May 13, 2017
a484fad
fixed stock data
eating247 May 13, 2017
4e6a1a1
start building portfolio table
eating247 May 13, 2017
c24ffd1
updating date in portfolio view
eating247 May 13, 2017
9901492
refactor updating variables
eating247 May 13, 2017
47c8671
portfolio filtering for dates before current selected date
eating247 May 14, 2017
ece46f8
trying again with populating portfolio table
eating247 May 14, 2017
57e54e9
basic portfolio calculations working
eating247 May 14, 2017
de98393
prices displaying in portfolio
eating247 May 14, 2017
c2e6a67
correct portfolio calculations
eating247 May 14, 2017
0b4edf7
populate portfolio overview table
eating247 May 14, 2017
e580135
configure portfolio trade link
eating247 May 14, 2017
f271116
add validations for trading
eating247 May 14, 2017
6af65ee
add stocks
eating247 May 14, 2017
2284bd8
editing comments
eating247 May 14, 2017
2b222c9
refactor stock table with row directives
eating247 May 14, 2017
0f88fdf
refactor portfolio header to transcluded directive
eating247 May 14, 2017
a4232d8
refactor transaction table with directives
eating247 May 14, 2017
b077c0a
change portfolio welcome screen + refactor into directive
eating247 May 14, 2017
e8eba6f
more styling
eating247 May 14, 2017
e2140e4
format portfolio state links
eating247 May 14, 2017
ec641af
fix link css + add notes for user flow
eating247 May 14, 2017
195e3c7
refactor portfolio table with directives
eating247 May 14, 2017
ba6d342
more styling
eating247 May 14, 2017
8a0e8f1
styling for trade form
eating247 May 14, 2017
b192c97
change wording in flash
eating247 May 14, 2017
ab61f30
position portfolio header buttons
eating247 May 14, 2017
175fa2a
add images for readme
eating247 May 14, 2017
7769bc3
edit readme
eating247 May 14, 2017
d4e5ffc
edit readme
eating247 May 14, 2017
a958156
more edits
eating247 May 14, 2017
01be738
organize screenshots
eating247 May 14, 2017
925c865
edit readme
eating247 May 14, 2017
57e6401
update screenshots
eating247 May 14, 2017
2dfa291
more readme updates
eating247 May 14, 2017
0697306
change formatting for negative amounts
eating247 May 14, 2017
ef723c2
refactor and identify date initialization bug
eating247 May 14, 2017
0db8491
welcome screen conditional on trades instead of positions
eating247 May 14, 2017
42f2269
fix date welcome view and change location of trade column
eating247 May 15, 2017
af75bf4
more chnages to readme
eating247 May 16, 2017
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
27 changes: 24 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
# assignment_fideligard_spa
Buy low, sell high.
# fideligard

[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)
An AngularJS single-page web application using UI-Router multi-view states, NoSQL data modeling, and modular code to create a historical stock portfolio simulator with trading data via the Yahoo Finance API.

To fire on local server, `git clone` the repository and run `ruby -run -e httpd . -p 3000`.

![Welcome](https://github.com/eating247/fideligard/blob/master/screenshots/1.png)

## Features

### User Flow

- Users are prompted to begin trading after stock data loads.
- Via the stocks panel, users enter trades through the trade form, where fields are auto-populated with respective stock and date info.
- Submission disabled if user attempts to buy more stocks than their available cash, or sell more quantity than they own.

![Trade](https://github.com/eating247/fideligard/blob/master/screenshots/2.png)

- All transactions up to selected date can be sorted according to date, price, ticker, or type (buy/sell).

![Transactions](https://github.com/eating247/fideligard/blob/master/screenshots/3.png)

- User's portfolio updates according to selected date, as adjusted through the date slider.

![Portfolio](https://github.com/eating247/fideligard/blob/master/screenshots/4.png)
26 changes: 26 additions & 0 deletions css/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.alert {
margin-top: -21px;
}

.template {
border: 3px solid black;
margin-bottom: 20px;
padding: 5px 10px 30px 15px;
}

.bottom {
margin-top: 25px;
}

table td {
border-top: none !important;
}

th {
white-space: nowrap;
}

button a, a:hover, a:focus {
color: white;
text-decoration: none;
}
81 changes: 81 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html ng-app="Fideligard">
<head>
<title>Fideligard</title>

<!-- Bootstrap CSS -->
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bootswatch/3.3.7/cosmo/bootstrap.min.css">

<link rel="stylesheet" type="text/css" href="css/main.css">

<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<!-- Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.15/angular-ui-router.min.js"></script>
</head>
<body>

<!-- nav -->
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">Fideligard Historical Portfolio Simulator</a>
</div>
</div>
</nav>

<!-- flash -->
<div class="alert alert-info alert-dismissable text-center">
<a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
<strong>Please be patient!</strong> Data may require a few seconds to load at start.
<br>
<small>*This app is dependent on the Yahoo Finance API. Please refresh the page if the Stocks panel remains empty.</small>
</div>

<div class="container">
<div class="row">

<!-- stocks panel -->
<div class="col-sm-4">
<div ui-view="stocks" class="template"></div>
</div>

<div class="col-sm-8">
<!-- date slider -->
<div ui-view="date" class="template"></div>

<!-- portfolio simulator -->
<div ui-view="portfolio" class="template"></div>
</div>

</div>
</div>

<script type="text/javascript" src="js/app.js"></script>

<!-- controllers -->
<script type="text/javascript" src="js/controllers/stocks_controller.js"></script>
<script type="text/javascript" src="js/controllers/date_controller.js"></script>
<script type="text/javascript" src="js/controllers/trade_controller.js"></script>
<script type="text/javascript" src="js/controllers/transactions_controller.js"></script>
<script type="text/javascript" src="js/controllers/portfolio_controller.js"></script>


<!-- services -->
<script type="text/javascript" src="js/services/date_service.js"></script>
<script type="text/javascript" src="js/services/stock_service.js"></script>
<script type="text/javascript" src="js/services/trade_service.js"></script>
<script type="text/javascript" src="js/services/portfolio_service.js"></script>
<!-- directives -->
<script type="text/javascript" src="js/directives/stock_table_row.js"></script>
<script type="text/javascript" src="js/directives/portfolio_header.js"></script>
<script type="text/javascript" src="js/directives/transaction_table_row.js"></script>
<script type="text/javascript" src="js/directives/welcome.js"></script>
<script type="text/javascript" src="js/directives/portfolio_positions_table_row.js"></script>
</body>
</html>
61 changes: 61 additions & 0 deletions js/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
var Fideligard = angular.module("Fideligard", ['ui.router']);

Fideligard.config(["$stateProvider", "$urlRouterProvider",
function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/stocks")

$stateProvider
.state('stocks', {
url: '/stocks',
views: {
"date": {
templateUrl: "js/templates/date.html",
controller: "DateCtrl"
},
"stocks": {
templateUrl: "js/templates/stocks.html",
controller: "StocksCtrl"
},
"portfolio": {
templateUrl: "js/templates/portfolio.html",
controller: "PortfolioCtrl"
}
},
resolve: {
stockData: function(StockService) {
return StockService.all();
}
}
})
.state('stocks.trade', {
url: '/trade',
params: { // default params
date: '2016-08-29',
symbol: "AAPL",
price: '106.82'
},
views: {
"portfolio@": {
templateUrl: "js/templates/trade.html",
controller: "TradeCtrl"
}
}
})
.state('stocks.transactions', {
url: '/transactions',
views: {
"portfolio@": {
templateUrl: "js/templates/transactions.html",
controller: "TransactionsCtrl"
}
}
})
}])

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

Fideligard.run(function($rootScope){
$rootScope.$on("$stateChangeError", console.log.bind(console));
});
17 changes: 17 additions & 0 deletions js/controllers/date_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Fideligard.controller("DateCtrl", ["$scope", "DateService", "StockService", "$rootScope",
function($scope, DateService, StockService, $rootScope) {

$scope.dateValue;

$scope.displayDate = function() {
return DateService.stringFormat();
}

$scope.setDateValue = function(dateForm) {
if (dateForm.date.$valid) {
$scope.date = DateService.setDateValue($scope.dateValue);
$rootScope.$broadcast('change.date');
}
}

}]);
21 changes: 21 additions & 0 deletions js/controllers/portfolio_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Fideligard.controller("PortfolioCtrl",
["$scope", "TradeService", "DateService", "PortfolioService",
function($scope, TradeService, DateService, PortfolioService) {

$scope.trades = TradeService.getTrades();

$scope.date = DateService.stringFormat();

$scope.positions = PortfolioService.getPositions();

$scope.overview = PortfolioService.getOverview();

// update portfolio table with current date selections
$scope.$on('change.date', function(event) {
$scope.trades = TradeService.getTrades();
$scope.date = DateService.hyphenFormat();
$scope.positions = PortfolioService.getPositions();
$scope.overview = PortfolioService.getOverview();
})

}]);
25 changes: 25 additions & 0 deletions js/controllers/stocks_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Fideligard.controller("StocksCtrl",
["$scope", "DateService", "StockService", "stockData", "$state",
function($scope, DateService, StockService, stockData, $state) {

$scope.displayDate = DateService.stringFormat();

$scope.date = DateService.hyphenFormat();

$scope.symbolFilterValue = false;

$scope.changeSymbolFilter = function() {
$scope.symbolFilterValue = !$scope.symbolFilterValue;
}

$scope.tableData = StockService.formatStockData();

// update stock table with new date selections
$scope.$on('change.date', function(event) {
$scope.date = DateService.hyphenFormat();
$scope.displayDate = DateService.stringFormat();
$scope.tableData = StockService.formatStockData();
})


}]);
41 changes: 41 additions & 0 deletions js/controllers/trade_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Fideligard.controller("TradeCtrl",
["$scope", "$stateParams", "StockService", "TradeService", "$state", "PortfolioService",
function($scope, $stateParams, StockService, TradeService, $state, PortfolioService) {

var _stocks = StockService.formatStockData();

// convert params into newTrade
$scope.newTrade = {
date: $stateParams.date,
price: $stateParams.price,
symbol: $stateParams.symbol,
quantity: 10,
type: true,
};

$scope.cash = TradeService.getCash();

$scope.cost = function() {
return !isNaN($scope.newTrade.quantity) ? ($scope.newTrade.quantity * $scope.newTrade.price) : '--';
}

$scope.orderStatus = function() {
if ($scope.newTrade.type) {
// if buying: make sure cash can cover trade
return $scope.cost() < $scope.cash ? true : false;
} else {
// if selling: cannot sell more quantity than they own
var position = PortfolioService.findPos($scope.newTrade.symbol)
return position && (position.quantity >= $scope.newTrade.quantity) ? true: false;
}
}

$scope.submitTrade = function() {
// validate + store in trade service
if ($scope.orderStatus()) {
TradeService.save($scope.newTrade);
$state.go('stocks.transactions');
}
}

}]);
19 changes: 19 additions & 0 deletions js/controllers/transactions_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Fideligard.controller("TransactionsCtrl",
["$scope", "TradeService",
function($scope, TradeService) {

$scope.transactions = TradeService.getTrades();

$scope.changeSort = function(arg) {
$scope.sortType = arg;
$scope.sortValue = !$scope.sortValue;
}

$scope.sortDisplay = function(arg) {
if ($scope.sortType === arg) {
return $scope.sortValue ? 'glyphicon glyphicon-triangle-top' : 'glyphicon glyphicon-triangle-bottom';
}
}


}]);
11 changes: 11 additions & 0 deletions js/directives/portfolio_header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Fideligard.directive('portfolioHeader', function(){
return {
templateUrl: "js/templates/portfolio_header.html",
restrict: "A",
transclude: true,
scope: {
stock: "=",
date: "="
}
};
});
10 changes: 10 additions & 0 deletions js/directives/portfolio_positions_table_row.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Fideligard.directive('portfolioPositionsTableRow', function(){
return {
templateUrl: "js/templates/portfolio_positions_table_row.html",
restrict: "A",
scope: {
position: "=",
date: "="
}
};
});
10 changes: 10 additions & 0 deletions js/directives/stock_table_row.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Fideligard.directive('stockTableRow', function(){
return {
templateUrl: "js/templates/stock_table_row.html",
restrict: "A",
scope: {
stock: "=",
date: "="
}
};
});
9 changes: 9 additions & 0 deletions js/directives/transaction_table_row.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Fideligard.directive('transactionTableRow', function(){
return {
templateUrl: "js/templates/transaction_table_row.html",
restrict: "A",
scope: {
transaction: "=",
}
};
});
6 changes: 6 additions & 0 deletions js/directives/welcome.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Fideligard.directive('welcome', function(){
return {
templateUrl: "js/templates/welcome.html",
restrict: "A",
};
});
Loading