Added Work directory
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
# Course Setup and Overview
|
||||
|
||||
Welcome to Practical Python Programming!
|
||||
Welcome to Practical Python Programming! This page has some important information
|
||||
about course setup and logistics.
|
||||
|
||||
## Course Duration and Time Requirements
|
||||
|
||||
This course was originally given as an instructor-led in-person
|
||||
training that spanned 3 to 4 days. To complete the course in its
|
||||
entirety, you should plan on committing 25-35 hours of work.
|
||||
|
||||
## Setup and Python Installation
|
||||
|
||||
@@ -54,18 +61,30 @@ bash %
|
||||
With this option, you just won't be able to commit code changes except
|
||||
to the local copy on your machine.
|
||||
|
||||
## File Layout
|
||||
## Coursework Layout
|
||||
|
||||
Do all of your coding work in the `Work/` directory. Within that directory,
|
||||
there is a `Data/` directory. The `Data/` directory contains a variety of
|
||||
datafiles and other scripts used during the course. You will frequently have
|
||||
to access files in `Data/`. Course exercises are written with the assumption
|
||||
that you are creating programs in the `Work/` directory.
|
||||
Do all of your coding work in the `Work/` directory. Within that
|
||||
directory, there is a `Data/` directory. The `Data/` directory
|
||||
contains a variety of datafiles and other scripts used during the
|
||||
course. You will frequently have to access files located in `Data/`.
|
||||
Course exercises are written with the assumption that you are creating
|
||||
programs in the `Work/` directory.
|
||||
|
||||
## Solutions
|
||||
## Course Order
|
||||
|
||||
Course material should be completed in section order, starting with
|
||||
section 1. Course exercises in later sections build upon code written in
|
||||
earlier sections.
|
||||
|
||||
## Solution Code
|
||||
|
||||
The `Solutions/` directory contains full solution code to selected exercises.
|
||||
Feel free to look at this if you need a hint.
|
||||
Feel free to look at this if you need a hint. To get the most out of the
|
||||
course, you should try to create your own solutions first.
|
||||
|
||||
[Contents](Contents)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2341
Work/Data/dowstocks.csv
Executable file
2341
Work/Data/dowstocks.csv
Executable file
File diff suppressed because it is too large
Load Diff
8
Work/Data/missing.csv
Executable file
8
Work/Data/missing.csv
Executable file
@@ -0,0 +1,8 @@
|
||||
name,shares,price
|
||||
"AA",100,32.20
|
||||
"IBM",50,91.10
|
||||
"CAT",150,83.44
|
||||
"MSFT",,51.23
|
||||
"GE",95,40.37
|
||||
"MSFT",50,65.10
|
||||
"IBM",,70.44
|
||||
|
8
Work/Data/portfolio.csv
Executable file
8
Work/Data/portfolio.csv
Executable file
@@ -0,0 +1,8 @@
|
||||
name,shares,price
|
||||
"AA",100,32.20
|
||||
"IBM",50,91.10
|
||||
"CAT",150,83.44
|
||||
"MSFT",200,51.23
|
||||
"GE",95,40.37
|
||||
"MSFT",50,65.10
|
||||
"IBM",100,70.44
|
||||
|
BIN
Work/Data/portfolio.csv.gz
Executable file
BIN
Work/Data/portfolio.csv.gz
Executable file
Binary file not shown.
8
Work/Data/portfolio.dat
Executable file
8
Work/Data/portfolio.dat
Executable file
@@ -0,0 +1,8 @@
|
||||
name shares price
|
||||
"AA" 100 32.20
|
||||
"IBM" 50 91.10
|
||||
"CAT" 150 83.44
|
||||
"MSFT" 200 51.23
|
||||
"GE" 95 40.37
|
||||
"MSFT" 50 65.10
|
||||
"IBM" 100 70.44
|
||||
5
Work/Data/portfolio2.csv
Normal file
5
Work/Data/portfolio2.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
name,shares,price
|
||||
"AA",50,27.10
|
||||
"HPQ",250,43.15
|
||||
"MSFT",25,50.15
|
||||
"GE",125,52.10
|
||||
|
16
Work/Data/portfolioblank.csv
Normal file
16
Work/Data/portfolioblank.csv
Normal file
@@ -0,0 +1,16 @@
|
||||
name,shares,price
|
||||
|
||||
"AA",100,32.20
|
||||
|
||||
"IBM",50,91.10
|
||||
|
||||
"CAT",150,83.44
|
||||
|
||||
"MSFT",200,51.23
|
||||
|
||||
"GE",95,40.37
|
||||
|
||||
"MSFT",50,65.10
|
||||
|
||||
"IBM",100,70.44
|
||||
|
||||
|
8
Work/Data/portfoliodate.csv
Normal file
8
Work/Data/portfoliodate.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
name,date,time,shares,price
|
||||
"AA","6/11/2007","9:50am",100,32.20
|
||||
"IBM","5/13/2007","4:20pm",50,91.10
|
||||
"CAT","9/23/2006","1:30pm",150,83.44
|
||||
"MSFT","5/17/2007","10:30am",200,51.23
|
||||
"GE","2/1/2006","10:45am",95,40.37
|
||||
"MSFT","10/31/2006","12:05pm",50,65.10
|
||||
"IBM","7/9/2006","3:15pm",100,70.44
|
||||
|
31
Work/Data/prices.csv
Normal file
31
Work/Data/prices.csv
Normal file
@@ -0,0 +1,31 @@
|
||||
"AA",9.22
|
||||
"AXP",24.85
|
||||
"BA",44.85
|
||||
"BAC",11.27
|
||||
"C",3.72
|
||||
"CAT",35.46
|
||||
"CVX",66.67
|
||||
"DD",28.47
|
||||
"DIS",24.22
|
||||
"GE",13.48
|
||||
"GM",0.75
|
||||
"HD",23.16
|
||||
"HPQ",34.35
|
||||
"IBM",106.28
|
||||
"INTC",15.72
|
||||
"JNJ",55.16
|
||||
"JPM",36.90
|
||||
"KFT",26.11
|
||||
"KO",49.16
|
||||
"MCD",58.99
|
||||
"MMM",57.10
|
||||
"MRK",27.58
|
||||
"MSFT",20.89
|
||||
"PFE",15.19
|
||||
"PG",51.94
|
||||
"T",24.79
|
||||
"UTX",52.61
|
||||
"VZ",29.26
|
||||
"WMT",49.74
|
||||
"XOM",69.35
|
||||
|
||||
|
183
Work/Data/stocksim.py
Executable file
183
Work/Data/stocksim.py
Executable file
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env python
|
||||
# stocksim.py
|
||||
#
|
||||
# Stock market simulator. This simulator creates stock market
|
||||
# data and provides it in several different ways:
|
||||
#
|
||||
# 1. Makes periodic updates to a log file stocklog.dat
|
||||
# 2. Provides stock data through an embedded HTTP server.
|
||||
#
|
||||
# The purpose of this module is to provide data to the user
|
||||
# in different ways in order to write interesting Python examples
|
||||
|
||||
import math
|
||||
import time
|
||||
|
||||
history_file = "dowstocks.csv"
|
||||
|
||||
# Convert a time string such as "4:00pm" to minutes past midnight
|
||||
def minutes(tm):
|
||||
am_pm = tm[-2:]
|
||||
fields = tm[:-2].split(":")
|
||||
hour = int(fields[0])
|
||||
minute = int(fields[1])
|
||||
if hour == 12:
|
||||
hour = 0
|
||||
if am_pm == 'pm':
|
||||
hour += 12
|
||||
return hour*60 + minute
|
||||
|
||||
# Convert time in minutes to a format string
|
||||
def minutes_to_str(m):
|
||||
frac,m = math.modf(m)
|
||||
hours = m//60
|
||||
minutes = m % 60
|
||||
seconds = frac * 60
|
||||
return "%02d:%02d.%02.f" % (hours,minutes,seconds)
|
||||
|
||||
# Read the stock history file as a list of lists
|
||||
def read_history(filename):
|
||||
result = []
|
||||
f = open(filename)
|
||||
next(f)
|
||||
for line in f:
|
||||
str_fields = line.strip().split(",")
|
||||
fields = [eval(x) for x in str_fields]
|
||||
fields[3] = minutes(fields[3])
|
||||
result.append(fields)
|
||||
return result
|
||||
|
||||
# Format CSV record
|
||||
def csv_record(fields):
|
||||
s = '"%s",%0.2f,"%s","%s",%0.2f,%0.2f,%0.2f,%0.2f,%d' % tuple(fields)
|
||||
return s
|
||||
|
||||
class StockTrack(object):
|
||||
def __init__(self,name):
|
||||
self.name = name
|
||||
self.history = []
|
||||
self.price = 0
|
||||
self.time = 0
|
||||
self.index = 0
|
||||
self.open = 0
|
||||
self.low = 0
|
||||
self.high = 0
|
||||
self.volume = 0
|
||||
self.initial = 0
|
||||
self.change = 0
|
||||
self.date = ""
|
||||
def add_data(self,record):
|
||||
self.history.append(record)
|
||||
def reset(self,time):
|
||||
self.time = time
|
||||
# Sort the history by time
|
||||
self.history.sort(key=lambda t:t[3])
|
||||
# Find the first entry who's time is behind the given time
|
||||
self.index = 0
|
||||
while self.index < len(self.history):
|
||||
if self.history[self.index][3] > time:
|
||||
break
|
||||
self.index += 1
|
||||
self.open = self.history[0][5]
|
||||
self.initial = self.history[0][1] - self.history[0][4]
|
||||
self.date = self.history[0][2]
|
||||
self.update()
|
||||
self.low = self.price
|
||||
self.high = self.price
|
||||
|
||||
# Calculate interpolated value of a given field based on
|
||||
# current time
|
||||
def interpolate(self,field):
|
||||
first = self.history[self.index][field]
|
||||
next = self.history[self.index+1][field]
|
||||
first_t = self.history[self.index][3]
|
||||
next_t = self.history[self.index+1][3]
|
||||
try:
|
||||
slope = (next - first)/(next_t-first_t)
|
||||
return first + slope*(self.time - first_t)
|
||||
except ZeroDivisionError:
|
||||
return first
|
||||
|
||||
# Update all computed values
|
||||
def update(self):
|
||||
self.price = round(self.interpolate(1),2)
|
||||
self.volume = int(self.interpolate(-1))
|
||||
if self.price < self.low:
|
||||
self.low = self.price
|
||||
if self.price >= self.high:
|
||||
self.high = self.price
|
||||
self.change = self.price - self.initial
|
||||
|
||||
# Increment the time by a delta
|
||||
def incr(self,dt):
|
||||
self.time += dt
|
||||
if self.index < (len(self.history) - 2):
|
||||
while self.index < (len(self.history) - 2) and self.time >= self.history[self.index+1][3]:
|
||||
self.index += 1
|
||||
self.update()
|
||||
|
||||
def make_record(self):
|
||||
return [self.name,round(self.price,2),self.date,minutes_to_str(self.time),round(self.change,2),self.open,round(self.high,2),
|
||||
round(self.low,2),self.volume]
|
||||
|
||||
class MarketSimulator(object):
|
||||
def __init__(self):
|
||||
self.stocks = { }
|
||||
self.prices = { }
|
||||
self.time = 0
|
||||
self.observers = []
|
||||
def register(self,observer):
|
||||
self.observers.append(observer)
|
||||
|
||||
def publish(self,record):
|
||||
for obj in self.observers:
|
||||
obj.update(record)
|
||||
def add_history(self,filename):
|
||||
hist = read_history(filename)
|
||||
for record in hist:
|
||||
if record[0] not in self.stocks:
|
||||
self.stocks[record[0]] = StockTrack(record[0])
|
||||
self.stocks[record[0]].add_data(record)
|
||||
|
||||
def reset(self,time):
|
||||
self.time = time
|
||||
for s in self.stocks.values():
|
||||
s.reset(time)
|
||||
|
||||
# Run forever. Dt is in seconds
|
||||
def run(self,dt):
|
||||
for s in self.stocks:
|
||||
self.prices[s] = self.stocks[s].price
|
||||
self.publish(self.stocks[s].make_record())
|
||||
while self.time < 1000:
|
||||
for s in self.stocks:
|
||||
self.stocks[s].incr(dt/60.0) # Increment is in minutes
|
||||
if self.stocks[s].price != self.prices[s]:
|
||||
self.prices[s] = self.stocks[s].price
|
||||
self.publish(self.stocks[s].make_record())
|
||||
time.sleep(dt)
|
||||
self.time += (dt/60.0)
|
||||
|
||||
|
||||
class BasicPrinter(object):
|
||||
def update(self,record):
|
||||
print(csv_record(record))
|
||||
|
||||
class LogPrinter(object):
|
||||
def __init__(self,filename):
|
||||
self.f = open(filename,"w")
|
||||
def update(self,record):
|
||||
self.f.write(csv_record(record)+"\n")
|
||||
self.f.flush()
|
||||
|
||||
m = MarketSimulator()
|
||||
m.add_history(history_file)
|
||||
m.reset(minutes("9:30am"))
|
||||
|
||||
m.register(BasicPrinter())
|
||||
m.register(LogPrinter("stocklog.csv"))
|
||||
|
||||
m.run(1)
|
||||
|
||||
|
||||
|
||||
8
Work/README.md
Normal file
8
Work/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Work Area
|
||||
|
||||
Do all of your coding work here, in the `Work/` directory. A number of starting
|
||||
files have been given (`bounce.py`, `mortgage.py`, `pcost.py`, etc.) along with
|
||||
their corresponding exercise number.
|
||||
|
||||
Many of the programs you write reference files found in the `Data/` directory.
|
||||
That is also located here.
|
||||
3
Work/bounce.py
Normal file
3
Work/bounce.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# bounce.py
|
||||
#
|
||||
# Exercise 1.5
|
||||
3
Work/fileparse.py
Normal file
3
Work/fileparse.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# fileparse.py
|
||||
#
|
||||
# Exercise 3.3
|
||||
3
Work/mortgage.py
Normal file
3
Work/mortgage.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# mortgage.py
|
||||
#
|
||||
# Exercise 1.7
|
||||
3
Work/pcost.py
Normal file
3
Work/pcost.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# pcost.py
|
||||
#
|
||||
# Exercise 1.27
|
||||
3
Work/report.py
Normal file
3
Work/report.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# report.py
|
||||
#
|
||||
# Exercise 2.4
|
||||
Reference in New Issue
Block a user