Skip to content
27 changes: 27 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@ import 'foundation-sites/dist/foundation.css';
import 'css/app.css';

import $ from 'jquery';
import _ from 'underscore';


import Simulator from 'models/simulator';
import QuoteList from 'collections/quote_list';
import Quote from 'models/quote';
import QuoteListView from './views/quote_list_view';
import Order from 'models/order';
import OrderList from 'collections/order_list';
import OrderListView from './views/order_list_view';

const quoteData = [
{
Expand All @@ -31,5 +38,25 @@ $(document).ready(function() {
quotes: quotes,
});

const quoteListView = new QuoteListView({
model: quotes,
template: _.template($('#quote-template').html()),
tradeTemplate: _.template($('#trade-template').html()),
el: 'main'
});

quotes.each((quote) => {
$('select').append(`<option>${quote.get('symbol')}</option>`);
});

const orders = new OrderList;

const orderListView = new OrderListView({
model: orders,
template: _.template($('#order-template').html()),
el: 'main'
});
orderListView.render();
quoteListView.renderQuote();
simulator.start();
});
12 changes: 12 additions & 0 deletions src/collections/order_list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// list of all open orders
// Orders are listed with the oldest at the top.
// Each open order entry in the list includes the symbol being ordered, whether it is a buy or sell order, the target price, and a cancel button.

import Backbone from 'backbone';
import Order from 'models/order';

const OrderList = Backbone.Collection.extend({
model: Order,
});

export default OrderList;
22 changes: 22 additions & 0 deletions src/models/order.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Backbone from 'backbone';
import Quote from 'models/quote';
// order needs quote
// Buy and Sell button creates the order

// order is listening to quote for changes in price
// when it hears the price changes the handler will have some logic to determine if the price is at a level in which to buy or sell

// before you have the quote buy or sell, you should destroy the order - to prevent duplicate buying or selling

const Order = Backbone.Model.extend({
initialize: function(attributes) {
},
validate: function(attributes) {
const errors = {};

console.log(attributes);
},

});

export default Order;
4 changes: 2 additions & 2 deletions src/models/quote.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ const Quote = Backbone.Model.extend({
},

buy() {
// Implement this function to increase the price by $1.00
this.set('price', this.get('price') + 1.00);
},

sell() {
// Implement this function to decrease the price by $1.00
this.set('price', this.get('price') - 1.00);
},
});

Expand Down
13 changes: 13 additions & 0 deletions src/views/form_view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// import Backbone from 'backbone';
// import Order from 'models/order';
//
// const FormView = Backbone.View.extend({
// initialize(params) {
// this.template = params.template;
// },
// createOrder: {
// const order = new Order({
//
// })
// }
// })
60 changes: 60 additions & 0 deletions src/views/order_list_view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Backbone from 'backbone';
import Order from 'models/order';
import _ from 'underscore';
import OrderList from 'collections/order_list';
import OrderView from 'views/order_view';


const OrderListView = Backbone.View.extend({
initialize(params) {
this.template = params.template;
this.listenTo(this.model, 'update', this.render);
},
render() {
this.$('#orders').empty();

this.model.each((order) => {
console.log(`rendering ${order}`);
const orderView = new OrderView({
model: order,
template: this.template,
tagName: 'li',
className: 'order',
});
this.$('#orders').append(orderView.render().$el);
});
return this;
},
events: {
'click button.btn-buy': 'newBuy',
'click button.btn-sell': 'newSell'
},
getFormData: function() {
const formData = {
// buy: false,
symbol: this.$('select option:selected').text(),
targetPrice: parseFloat(this.$('input').val()),
};
console.log(formData);
return formData;
},
newBuy: function(e) {
e.preventDefault();
this.createOrder(true);
},
newSell: function(e) {
e.preventDefault();
this.createOrder(false);
},
createOrder: function(buy) {

let formData = this.getFormData();
formData.buy = buy;
const newOrder = new Order(formData);
this.model.add(newOrder);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now you only have the symbol for this quote, since that's what you get when you read the form. However, in order to connect all the pieces, you really need the Quote itself, not just the symbol. That will let the Order listen to events on the quote, validate the initial buy/sell price, etc.

One way to do this would be for the OrderListView to know about the QuoteList collection, passing it in as an extra property to the constructor from app.js. Then in QuoteList you could write a function that, given a symbol, returns the corresponding quote.


},

});

export default OrderListView;
19 changes: 19 additions & 0 deletions src/views/order_view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Backbone from 'backbone';
import Order from 'models/order';

const OrderView = Backbone.View.extend({
initialize(params) {
this.template = params.template;
},
render() {
console.log(this.model.attributes);
const compiledTemplate = this.template(this.model.attributes);
console.log('rendered 1');

this.$el.html(compiledTemplate);

return this;
},
});

export default OrderView;
34 changes: 34 additions & 0 deletions src/views/quote_list_view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Backbone from 'backbone';
import _ from 'underscore';
import Quote from 'models/quote';
import QuoteList from 'collections/quote_list';
import QuoteView from 'views/quote_view';

const QuoteListView = Backbone.View.extend({
initialize(params) {
this.template = params.template;
this.tradeTemplate = params.tradeTemplate;
this.listenTo(this.model, 'update', this.renderQuote);
},
renderQuote() {
this.$('#quotes').empty();

this.model.each((quote) => {
const quoteView = new QuoteView({
model: quote,
template: this.template,
className: 'quote',
});
this.listenTo(quoteView, 'tradeUpdate', this.trade);
this.$('#quotes').append(quoteView.render().$el);
});
return this;
},
trade: function(quoteView) {
const compiledTradeTemplate = this.tradeTemplate(quoteView.model.toJSON());
this.$('#trades').prepend(compiledTradeTemplate);
},

});

export default QuoteListView;
34 changes: 34 additions & 0 deletions src/views/quote_view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Backbone from 'backbone';
import Quote from 'models/quote';

const QuoteView = Backbone.View.extend({
initialize(params) {
this.template = params.template;

this.listenTo(this.model, 'change', this.render);
},
render() {

const compiledTemplate = this.template(this.model.toJSON());

this.$el.html(compiledTemplate);

return this;
},
events: {
'click button.btn-buy': 'buy',
'click button.btn-sell': 'sell'
},
buy() {
this.model.set('buy', true);
this.trigger('tradeUpdate', this);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I like the attribute name buy. A more descriptive way to go might be to call the attribute 'lastTradeType' and set it to 'buy' or 'sell'.

Since the type of the most recent trade isn't really relevant for the quote, an even better strategy would be to not set it on the model at all, but provide it as an extra parameter when you trigger the event:

this.trigger('tradeUpdate', this, true);

And then the event listener in QuoteListView:

trade: function(quoteView, buy) {
  const tradeData = quoteView.model.toJSON();
  tradeData.buy = buy;
  const compiledTradeTemplate = this.tradeTemplate(tradeData);
  // ...
}

this.model.buy();
},
sell() {
this.model.set('buy', false);
this.trigger('tradeUpdate', this);
this.model.sell();
},
});

export default QuoteView;