Snippets
Created by
Michael Lee
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | from flask import Flask, request, render_template, jsonify, redirect
import urllib.request, urllib.parse, urllib.error
import json
import datetime
app = Flask(__name__)
app.debug = True
stocks = []
date = datetime.date(2000, 1, 3)
cash = 100000
class Stock:
def __init__(self, symbol, quantity, purch_date, init_price):
self.symbol = symbol
self.quantity = quantity
self.purch_date = purch_date
self.init_price = init_price
self.earnings = 0
self.last_price = init_price
self.last_earning = 0
@app.route('/')
def index():
return render_template('paper.html', date=date, stocks=stocks, cash=cash)
@app.route('/advance/<int:days>')
def advance_day(days):
global date
date += datetime.timedelta(days=days)
while not is_trading_day(date):
date += datetime.timedelta(days=1)
update_stocks()
return jsonify(date=date.isoformat(),
stocks=[s.__dict__ for s in stocks])
def update_stocks():
for s in stocks:
q = fetch_quotes(s.symbol, date, date)
if q:
s.earnings = s.quantity * (float(q['Close']) - s.init_price)
s.last_earning = s.quantity * (float(q['Close']) - s.last_price)
s.last_price = float(q['Close'])
@app.route('/trade')
def trade():
global cash
symbol = request.args['symbol']
quantity = int(request.args['quantity'])
q = fetch_quotes(symbol, date, date)
if q:
s = Stock(symbol, quantity, date, float(q['Open']))
cash -= quantity * s.init_price
stocks.append(s)
return jsonify(cash=cash,
stocks=[s.__dict__ for s in stocks])
else:
return jsonify({})
@app.route('/sell/<int:sidx>')
def sell(sidx):
global cash
stock = stocks[sidx]
cash += stock.quantity * stock.last_price
del stocks[sidx]
return jsonify(cash=cash,
stocks=[s.__dict__ for s in stocks])
@app.route('/lookup/<sym>')
def lookup(sym):
quotes = fetch_quotes(sym, date-datetime.timedelta(30), date)
if quotes:
return jsonify(quotes)
else:
return jsonify({})
def is_trading_day(date):
return fetch_quotes('YHOO', date, date) is not None
# noinspection SqlNoDataSourceInspection
def fetch_quotes(symbol, start_date, end_date):
base_url = 'http://query.yahooapis.com/v1/public/yql'
yql = ('select * from yahoo.finance.historicaldata where symbol = "' + symbol
+ '" and startDate = "' + start_date.isoformat()
+ '" and endDate = "' + end_date.isoformat() + '"')
req_url = (base_url + '?q=' + urllib.parse.quote(yql)
+ '&env=http%3A%2F%2Fdatatables.org%2Falltables.env&format=json')
try:
response = urllib.request.urlopen(req_url)
results = json.loads(response.read().decode('utf-8'))['query']['results']
if results:
return results['quote']
else:
return None
except urllib.error.HTTPError:
return None
@app.route('/reset', methods=['POST'])
def reset():
global cash, date
stocks.clear()
cash = 100000
date = datetime.date(2000, 1, 3)
return redirect('/')
if __name__ == '__main__':
app.run()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | <!DOCTYPE html>
<html>
<head>
<title>Simple Paper Trader</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script src="https://cdn.rawgit.com/etpinard/plotlyjs-finance/master/plotlyjs-finance.js"></script>
</head>
<body>
<p>
Date: <span id="date">{{ date.isoformat() }}</span>
<button id="advance_day">Advance day</button>
<button id="advance_month">Advance month</button>
<button id="advance_year">Advance year</button>
<button id="restart">Restart</button>
</p>
<h3>Portfolio</h3>
<ol id="portfolio">
{% for s in stocks %}
<li>
Symbol: {{ s.symbol.upper() }},
Quantity: {{ s.quantity }},
Price: {{ '${:,.2f}'.format(s.last_price) }},
Gains: {{ '${:,.2f}'.format(s.earnings) }}
<button class="sell" value="{{ loop.index0 }}">Sell</button>
</li>
{% endfor %}
</ol>
<p>
Cash on hand: <span id="cash">{{ "${:,.2f}".format(cash) }}</span>
</p>
<hr>
<h3>Trade</h3>
<form id="trade">
<label for="symbol">Symbol</label>
<input type="text" name="symbol" value="AAPL">
<label for="quantity">Quantity</label>
<input type="text" name="quantity" value="1">
<input type="Submit" value="Buy">
</form>
<hr>
<h3>Lookup</h3>
<form id="lookup">
<label for="symbol">Symbol</label>
<input id="lookup_symbol" type="text" name="symbol" value="AAPL">
<input type="Submit" value="Search">
</form>
<div id="plotly" style="width:700px;height:400px;"></div>
<script>
function formatCurrency(value) {
return '$' + value.toFixed(2).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
}
function advance(days) {
$.getJSON('/advance/' + days, function(data) {
$('#date').text(data.date);
updateStocks(data.stocks);
});
}
function updateStocks(stocks) {
$('#portfolio').html('');
var idx = 0;
$.map(stocks, function(s) {
$('#portfolio').append('<li>'
+ 'Symbol: ' + s.symbol.toUpperCase() + ', '
+ 'Quantity: ' + s.quantity + ', '
+ 'Price: ' + formatCurrency(s.last_price) + ', '
+ 'Gains: ' + formatCurrency(s.earnings)
+ '<button class="sell" value="' + idx + '">Sell</button>'
+ '</li>');
idx += 1;
});
$('.sell').click(function(e) {
$.getJSON('/sell/' + this.value, function(data) {
if (data) {
$('#cash').text(formatCurrency(data.cash));
updateStocks(data.stocks);
}
});
});
}
$(function() {
$('.sell').click(function(e) {
$.getJSON('/sell/' + this.value, function(data) {
if (data) {
$('#cash').text(formatCurrency(data.cash));
updateStocks(data.stocks);
}
});
});
$('#advance_day').click(function(e) {
advance(1);
});
$('#advance_month').click(function(e) {
advance(30);
});
$('#advance_year').click(function(e) {
advance(365);
});
$('#trade').submit(function(e) {
var sym = this.elements.symbol.value;
var qty = this.elements.quantity.value;
$.getJSON('/trade', { symbol: sym, quantity: qty }, function(data) {
if (data) {
$('#cash').text(formatCurrency(data.cash));
updateStocks(data.stocks);
}
});
e.preventDefault();
});
$('#lookup').submit(function(e) {
var sym = $('#lookup_symbol').val();
console.log(sym);
$.getJSON('/lookup/' + sym, function(quotes) {
if (quotes) {
var fig = PlotlyFinance.createCandlestick(
{
open: $.map(quotes, function (q) {
return parseFloat(q.Open)
}),
high: $.map(quotes, function (q) {
return parseFloat(q.High)
}),
low: $.map(quotes, function (q) {
return parseFloat(q.Low)
}),
close: $.map(quotes, function (q) {
return parseFloat(q.Close)
}),
dates: $.map(quotes, function (q) {
return new Date(q.Date)
})
}
);
Plotly.newPlot('plotly', fig.data, fig.layout);
}
});
e.preventDefault();
});
$('#restart').click(function() {
$.post('/reset', function() {
window.location.reload();
});
});
});
</script>
</body>
</html>
|
Comments (0)
You can clone a snippet to your computer for local editing. Learn more.