diff --git a/Work/Data/stocklog.csv b/Work/Data/stocklog.csv new file mode 100644 index 000000000..542a62d80 --- /dev/null +++ b/Work/Data/stocklog.csv @@ -0,0 +1,189 @@ +"AA",39.31,"6/11/2007","09:30.00",-0.35,39.67,39.31,39.31,75600 +"AIG",71.26,"6/11/2007","09:30.00",-0.27,71.29,71.26,71.26,73400 +"AXP",62.38,"6/11/2007","09:30.00",-0.66,62.79,62.38,62.38,834350 +"BA",98.31,"6/11/2007","09:30.00",0.12,98.25,98.31,98.31,37450 +"C",52.99,"6/11/2007","09:30.00",-0.34,53.20,52.99,52.99,82500 +"CAT",77.99,"6/11/2007","09:30.00",-0.53,78.32,77.99,77.99,169282 +"DD",50.60,"6/11/2007","09:30.00",-0.53,51.13,50.60,50.60,9750 +"DIS",34.04,"6/11/2007","09:30.00",-0.16,34.28,34.04,34.04,105100 +"GE",37.12,"6/11/2007","09:30.00",-0.20,37.07,37.12,37.12,175900 +"GM",31.50,"6/11/2007","09:30.00",0.50,31.00,31.50,31.50,177454 +"HD",37.62,"6/11/2007","09:30.00",-0.33,37.78,37.62,37.62,114969 +"HON",57.02,"6/11/2007","09:30.00",-0.36,57.25,57.02,57.02,111800 +"HPQ",45.59,"6/11/2007","09:30.00",-0.11,45.80,45.59,45.59,121100 +"IBM",102.77,"6/11/2007","09:30.00",-0.30,102.87,102.77,102.77,73900 +"INTC",21.82,"6/11/2007","09:30.00",-0.01,21.70,21.82,21.82,1796393 +"JNJ",62.08,"6/11/2007","09:30.00",-0.05,62.89,62.08,62.08,253400 +"JPM",50.25,"6/11/2007","09:30.00",-0.16,50.41,50.25,50.25,185650 +"KO",51.63,"6/11/2007","09:30.00",-0.04,51.67,51.63,51.63,3952150 +"MCD",50.80,"6/11/2007","09:30.00",-0.61,51.47,50.80,50.80,92400 +"MMM",85.75,"6/11/2007","09:30.00",-0.19,85.94,85.75,85.75,156100 +"MO",70.30,"6/11/2007","09:30.00",0.00,70.25,70.30,70.30,362600 +"MRK",49.66,"6/11/2007","09:30.00",-0.48,50.30,49.66,49.66,1254100 +"MSFT",29.95,"6/11/2007","09:30.00",-0.10,30.05,29.95,29.95,4861715 +"PFE",26.31,"6/11/2007","09:30.00",-0.21,26.50,26.31,26.31,436150 +"PG",62.61,"6/11/2007","09:30.00",-0.46,62.80,62.61,62.61,80754 +"T",39.87,"6/11/2007","09:30.00",-0.39,40.20,39.87,39.87,508700 +"UTX",69.71,"6/11/2007","09:30.00",-0.52,69.85,69.71,69.71,97050 +"VZ",42.78,"6/11/2007","09:30.00",-0.29,42.95,42.78,42.78,119300 +"WMT",49.87,"6/11/2007","09:30.00",-0.21,49.90,49.87,49.87,456450 +"XOM",82.64,"6/11/2007","09:30.00",-0.04,82.68,82.64,82.64,144750 +"AA",39.32,"6/11/2007","09:30.01",-0.34,39.67,39.32,39.31,75894 +"AXP",62.39,"6/11/2007","09:30.01",-0.65,62.79,62.39,62.38,834629 +"GE",37.13,"6/11/2007","09:30.01",-0.19,37.07,37.13,37.12,177339 +"XOM",82.63,"6/11/2007","09:30.01",-0.05,82.68,82.64,82.63,145684 +"HPQ",45.60,"6/11/2007","09:30.02",-0.10,45.80,45.60,45.59,122111 +"MCD",50.81,"6/11/2007","09:30.05",-0.60,51.47,50.81,50.80,93678 +"CAT",78.00,"6/11/2007","09:30.06",-0.52,78.32,78.00,77.99,170217 +"MRK",49.67,"6/11/2007","09:30.07",-0.47,50.30,49.67,49.66,1257973 +"JNJ",62.09,"6/11/2007","09:30.09",-0.04,62.89,62.09,62.08,256102 +"MO",70.29,"6/11/2007","09:30.09",-0.01,70.25,70.30,70.29,365314 +"PG",62.62,"6/11/2007","09:30.09",-0.45,62.80,62.62,62.61,86011 +"DIS",34.05,"6/11/2007","09:30.10",-0.15,34.28,34.05,34.04,107963 +"MMM",85.74,"6/11/2007","09:30.10",-0.20,85.94,85.75,85.74,157256 +"T",39.88,"6/11/2007","09:30.10",-0.38,40.20,39.88,39.87,514789 +"VZ",42.79,"6/11/2007","09:30.11",-0.28,42.95,42.79,42.78,123028 +"DD",50.61,"6/11/2007","09:30.13",-0.52,51.13,50.61,50.60,12897 +"MRK",49.68,"6/11/2007","09:30.13",-0.46,50.30,49.68,49.66,1261293 +"MCD",50.82,"6/11/2007","09:30.15",-0.59,51.47,50.82,50.80,96234 +"AIG",71.27,"6/11/2007","09:30.16",-0.26,71.29,71.27,71.26,78826 +"HON",57.03,"6/11/2007","09:30.16",-0.35,57.25,57.03,57.02,112829 +"IBM",102.78,"6/11/2007","09:30.17",-0.29,102.87,102.78,102.77,78308 +"CAT",78.01,"6/11/2007","09:30.18",-0.51,78.32,78.01,77.99,172087 +"AXP",62.40,"6/11/2007","09:30.19",-0.64,62.79,62.40,62.38,839662 +"HPQ",45.61,"6/11/2007","09:30.19",-0.09,45.80,45.61,45.59,130710 +"MRK",49.69,"6/11/2007","09:30.20",-0.45,50.30,49.69,49.66,1265166 +"C",53.00,"6/11/2007","09:30.21",-0.33,53.20,53.00,52.99,98739 +"PFE",26.32,"6/11/2007","09:30.21",-0.20,26.50,26.32,26.31,459451 +"WMT",49.86,"6/11/2007","09:30.21",-0.22,49.90,49.87,49.86,469268 +"AA",39.33,"6/11/2007","09:30.22",-0.33,39.67,39.33,39.31,82089 +"MCD",50.83,"6/11/2007","09:30.25",-0.58,51.47,50.83,50.80,98791 +"MO",70.28,"6/11/2007","09:30.26",-0.02,70.25,70.30,70.28,370443 +"MRK",49.70,"6/11/2007","09:30.26",-0.44,50.30,49.70,49.66,1268486 +"PG",62.63,"6/11/2007","09:30.26",-0.44,62.80,62.63,62.61,95941 +"JNJ",62.10,"6/11/2007","09:30.27",-0.03,62.89,62.10,62.08,261508 +"XOM",82.62,"6/11/2007","09:30.27",-0.06,82.68,82.64,82.62,169983 +"DIS",34.06,"6/11/2007","09:30.29",-0.14,34.28,34.06,34.04,113403 +"T",39.89,"6/11/2007","09:30.29",-0.37,40.20,39.89,39.87,526360 +"CAT",78.02,"6/11/2007","09:30.30",-0.50,78.32,78.02,77.99,173958 +"MMM",85.73,"6/11/2007","09:30.30",-0.21,85.94,85.75,85.73,159569 +"GM",31.49,"6/11/2007","09:30.31",0.49,31.00,31.50,31.49,223779 +"HD",37.63,"6/11/2007","09:30.31",-0.32,37.78,37.63,37.62,125653 +"MRK",49.71,"6/11/2007","09:30.33",-0.43,50.30,49.71,49.66,1272359 +"VZ",42.80,"6/11/2007","09:30.33",-0.27,42.95,42.80,42.78,130486 +"MCD",50.84,"6/11/2007","09:30.34",-0.57,51.47,50.84,50.80,101092 +"GE",37.14,"6/11/2007","09:30.35",-0.18,37.07,37.14,37.12,226299 +"JPM",50.26,"6/11/2007","09:30.35",-0.15,50.41,50.26,50.25,201735 +"UTX",69.72,"6/11/2007","09:30.35",-0.51,69.85,69.72,69.71,102577 +"HPQ",45.62,"6/11/2007","09:30.36",-0.08,45.80,45.62,45.59,139309 +"MSFT",29.96,"6/11/2007","09:30.36",-0.09,30.05,29.96,29.95,4932859 +"AXP",62.41,"6/11/2007","09:30.37",-0.63,62.79,62.41,62.38,844694 +"DD",50.62,"6/11/2007","09:30.37",-0.51,51.13,50.62,50.60,18707 +"MRK",49.72,"6/11/2007","09:30.39",-0.42,50.30,49.72,49.66,1275679 +"PG",62.64,"6/11/2007","09:30.42",-0.43,62.80,62.64,62.61,105288 +"CAT",78.03,"6/11/2007","09:30.43",-0.49,78.32,78.03,77.99,175984 +"MO",70.27,"6/11/2007","09:30.43",-0.03,70.25,70.30,70.27,375571 +"AA",39.34,"6/11/2007","09:30.44",-0.32,39.67,39.34,39.31,88579 +"MCD",50.85,"6/11/2007","09:30.44",-0.56,51.47,50.85,50.80,103649 +"JNJ",62.11,"6/11/2007","09:30.45",-0.02,62.89,62.11,62.08,266914 +"AIG",71.28,"6/11/2007","09:30.46",-0.25,71.29,71.28,71.26,89001 +"HON",57.04,"6/11/2007","09:30.46",-0.34,57.25,57.04,57.02,114759 +"MRK",49.73,"6/11/2007","09:30.46",-0.41,50.30,49.73,49.66,1279553 +"DIS",34.07,"6/11/2007","09:30.47",-0.13,34.28,34.07,34.04,118557 +"T",39.90,"6/11/2007","09:30.47",-0.36,40.20,39.90,39.87,537322 +"IBM",102.79,"6/11/2007","09:30.51",-0.28,102.87,102.79,102.77,87125 +"MMM",85.72,"6/11/2007","09:30.51",-0.22,85.94,85.75,85.72,161998 +"HPQ",45.63,"6/11/2007","09:30.52",-0.07,45.80,45.63,45.59,147403 +"MRK",49.74,"6/11/2007","09:30.52",-0.40,50.30,49.74,49.66,1282873 +"MCD",50.86,"6/11/2007","09:30.54",-0.55,51.47,50.86,50.80,106205 +"VZ",42.81,"6/11/2007","09:30.54",-0.26,42.95,42.81,42.78,137605 +"XOM",82.61,"6/11/2007","09:30.54",-0.07,82.68,82.64,82.61,195217 +"CAT",78.04,"6/11/2007","09:30.55",-0.48,78.32,78.04,77.99,177855 +"AXP",62.42,"6/11/2007","09:30.56",-0.62,62.79,62.42,62.38,850006 +"MRK",49.75,"6/11/2007","09:30.59",-0.39,50.30,49.75,49.66,1286746 +"PG",62.65,"6/11/2007","09:30.59",-0.42,62.80,62.65,62.61,115219 +"C",53.01,"6/11/2007","09:31.01",-0.32,53.20,53.01,52.99,129673 +"DD",50.63,"6/11/2007","09:31.01",-0.50,51.13,50.63,50.60,24517 +"INTC",21.83,"6/11/2007","09:31.01",0.00,21.70,21.83,21.82,1911365 +"MO",70.26,"6/11/2007","09:31.01",-0.04,70.25,70.30,70.26,381001 +"PFE",26.33,"6/11/2007","09:31.01",-0.19,26.50,26.33,26.31,503834 +"WMT",49.85,"6/11/2007","09:31.01",-0.23,49.90,49.87,49.85,493685 +"JNJ",62.12,"6/11/2007","09:31.02",-0.01,62.89,62.12,62.08,272020 +"MCD",50.87,"6/11/2007","09:31.03",-0.54,51.47,50.87,50.80,108506 +"MRK",49.76,"6/11/2007","09:31.05",-0.38,50.30,49.76,49.66,1290066 +"AA",39.35,"6/11/2007","09:31.06",-0.31,39.67,39.35,39.31,95069 +"DIS",34.08,"6/11/2007","09:31.06",-0.12,34.28,34.08,34.04,123997 +"T",39.91,"6/11/2007","09:31.06",-0.35,40.20,39.91,39.87,548893 +"CAT",78.05,"6/11/2007","09:31.07",-0.47,78.32,78.05,77.99,179726 +"GE",37.15,"6/11/2007","09:31.09",-0.17,37.07,37.15,37.12,275259 +"HPQ",45.64,"6/11/2007","09:31.09",-0.06,45.80,45.64,45.59,156002 +"JPM",50.27,"6/11/2007","09:31.09",-0.14,50.41,50.27,50.25,217361 +"UTX",69.73,"6/11/2007","09:31.09",-0.50,69.85,69.73,69.71,107946 +"MMM",85.71,"6/11/2007","09:31.11",-0.23,85.94,85.75,85.71,164312 +"MRK",49.77,"6/11/2007","09:31.12",-0.37,50.30,49.77,49.66,1293939 +"MCD",50.88,"6/11/2007","09:31.13",-0.53,51.47,50.88,50.80,111063 +"AXP",62.43,"6/11/2007","09:31.14",-0.61,62.79,62.43,62.38,855039 +"AIG",71.29,"6/11/2007","09:31.16",-0.24,71.29,71.29,71.26,99176 +"HON",57.05,"6/11/2007","09:31.16",-0.33,57.25,57.05,57.02,116689 +"KO",51.64,"6/11/2007","09:31.16",-0.03,51.67,51.64,51.63,3959559 +"PG",62.66,"6/11/2007","09:31.16",-0.41,62.80,62.66,62.61,125149 +"VZ",42.82,"6/11/2007","09:31.16",-0.25,42.95,42.82,42.78,145063 +"MO",70.25,"6/11/2007","09:31.18",-0.05,70.25,70.30,70.25,386129 +"MRK",49.78,"6/11/2007","09:31.18",-0.36,50.30,49.78,49.66,1297259 +"CAT",78.06,"6/11/2007","09:31.19",-0.46,78.32,78.06,77.99,181596 +"JNJ",62.13,"6/11/2007","09:31.20",0.00,62.89,62.13,62.08,277426 +"XOM",82.60,"6/11/2007","09:31.21",-0.08,82.68,82.64,82.60,220451 +"MCD",50.89,"6/11/2007","09:31.23",-0.52,51.47,50.89,50.80,113620 +"IBM",102.80,"6/11/2007","09:31.24",-0.27,102.87,102.80,102.77,95683 +"DD",50.64,"6/11/2007","09:31.25",-0.49,51.13,50.64,50.60,30327 +"DIS",34.09,"6/11/2007","09:31.25",-0.11,34.28,34.09,34.04,129438 +"MRK",49.79,"6/11/2007","09:31.25",-0.35,50.30,49.79,49.66,1301133 +"T",39.92,"6/11/2007","09:31.25",-0.34,40.20,39.92,39.87,560464 +"HPQ",45.65,"6/11/2007","09:31.26",-0.05,45.80,45.65,45.59,164601 +"MSFT",29.97,"6/11/2007","09:31.26",-0.08,30.05,29.97,29.95,5031669 +"AA",39.36,"6/11/2007","09:31.28",-0.30,39.67,39.36,39.31,101559 +"CAT",78.07,"6/11/2007","09:31.31",-0.45,78.32,78.07,77.99,183467 +"GM",31.48,"6/11/2007","09:31.31",0.48,31.00,31.50,31.48,313442 +"HD",37.64,"6/11/2007","09:31.31",-0.31,37.78,37.64,37.62,146333 +"MMM",85.70,"6/11/2007","09:31.31",-0.24,85.94,85.75,85.70,166625 +"MRK",49.80,"6/11/2007","09:31.31",-0.34,50.30,49.80,49.66,1304453 +"MCD",50.90,"6/11/2007","09:31.32",-0.51,51.47,50.90,50.80,115921 +"PG",62.67,"6/11/2007","09:31.32",-0.40,62.80,62.67,62.61,134496 +"AXP",62.44,"6/11/2007","09:31.33",-0.60,62.79,62.44,62.38,860351 +"MO",70.24,"6/11/2007","09:31.35",-0.06,70.25,70.30,70.24,391258 +"VZ",42.83,"6/11/2007","09:31.37",-0.24,42.95,42.83,42.78,152182 +"JNJ",62.14,"6/11/2007","09:31.38",0.01,62.89,62.14,62.08,282832 +"MRK",49.81,"6/11/2007","09:31.38",-0.33,50.30,49.81,49.66,1308326 +"C",53.02,"6/11/2007","09:31.41",-0.31,53.20,53.02,52.99,160606 +"PFE",26.34,"6/11/2007","09:31.41",-0.18,26.50,26.34,26.31,548217 +"WMT",49.84,"6/11/2007","09:31.41",-0.24,49.90,49.87,49.84,518102 +"HPQ",45.66,"6/11/2007","09:31.42",-0.04,45.80,45.66,45.59,172694 +"MCD",50.91,"6/11/2007","09:31.42",-0.50,51.47,50.91,50.80,118477 +"CAT",78.08,"6/11/2007","09:31.43",-0.44,78.32,78.08,77.99,185337 +"GE",37.16,"6/11/2007","09:31.43",-0.16,37.07,37.16,37.12,324219 +"JPM",50.28,"6/11/2007","09:31.43",-0.13,50.41,50.28,50.25,232987 +"UTX",69.74,"6/11/2007","09:31.43",-0.49,69.85,69.74,69.71,113315 +"DIS",34.10,"6/11/2007","09:31.44",-0.10,34.28,34.10,34.04,134878 +"MRK",49.82,"6/11/2007","09:31.44",-0.32,50.30,49.82,49.66,1311646 +"T",39.93,"6/11/2007","09:31.44",-0.33,40.20,39.93,39.87,572035 +"AIG",71.30,"6/11/2007","09:31.46",-0.23,71.29,71.30,71.26,109351 +"HON",57.06,"6/11/2007","09:31.46",-0.32,57.25,57.06,57.02,118619 +"XOM",82.59,"6/11/2007","09:31.47",-0.09,82.68,82.64,82.59,244750 +"DD",50.65,"6/11/2007","09:31.49",-0.48,51.13,50.65,50.60,36137 +"PG",62.68,"6/11/2007","09:31.49",-0.39,62.80,62.68,62.61,144426 +"AA",39.37,"6/11/2007","09:31.50",-0.29,39.67,39.37,39.31,108049 +"AXP",62.45,"6/11/2007","09:31.51",-0.59,62.79,62.45,62.38,865383 +"MMM",85.69,"6/11/2007","09:31.51",-0.25,85.94,85.75,85.69,168938 +"MRK",49.83,"6/11/2007","09:31.51",-0.31,50.30,49.83,49.66,1315519 +"MCD",50.92,"6/11/2007","09:31.52",-0.49,51.47,50.92,50.80,121034 +"MO",70.23,"6/11/2007","09:31.52",-0.07,70.25,70.30,70.23,396386 +"CAT",78.09,"6/11/2007","09:31.55",-0.43,78.32,78.09,77.99,187208 +"JNJ",62.15,"6/11/2007","09:31.55",0.02,62.89,62.15,62.08,287938 +"IBM",102.81,"6/11/2007","09:31.57",-0.26,102.87,102.81,102.77,104241 +"MRK",49.84,"6/11/2007","09:31.57",-0.30,50.30,49.84,49.66,1318839 +"VZ",42.84,"6/11/2007","09:31.58",-0.23,42.95,42.84,42.78,159301 +"HPQ",45.67,"6/11/2007","09:31.59",-0.03,45.80,45.67,45.59,181294 +"MCD",50.93,"6/11/2007","09:32.01",-0.48,51.47,50.93,50.80,123335 +"DIS",34.11,"6/11/2007","09:32.02",-0.09,34.28,34.11,34.04,140032 +"T",39.94,"6/11/2007","09:32.02",-0.32,40.20,39.94,39.87,582997 +"MRK",49.85,"6/11/2007","09:32.04",-0.29,50.30,49.85,49.66,1322713 diff --git a/Work/bounce.py b/Work/bounce.py index 3660ddd82..24a8be020 100644 --- a/Work/bounce.py +++ b/Work/bounce.py @@ -1,3 +1,13 @@ # bounce.py # # Exercise 1.5 + + +def bounce(ht,bounce_back): + for i in range(10): + ht = round(ht*bounce_back,4) + print(f'{i+1} {ht}') + print('{0:} {1:}'.format(i+1,ht)) + +if __name__ == '__main__': + bounce(100,3/5) diff --git a/Work/fileparse.py b/Work/fileparse.py index 1d499e733..0e02be107 100644 --- a/Work/fileparse.py +++ b/Work/fileparse.py @@ -1,3 +1,52 @@ # fileparse.py # # Exercise 3.3 + +# fileparse.py +import csv + +def parse_csv(lines, select=None, types=None, has_headers=True, delimiter=',', silence_errors=False): + ''' + Parse a CSV file into a list of records with type conversion. + ''' + if select and not has_headers: + raise RuntimeError('select requires column headers') + + rows = csv.reader(lines, delimiter=delimiter) + + # Read the file headers (if any) + headers = next(rows) if has_headers else [] + + # If specific columns have been selected, make indices for filtering and set output columns + indices = [] + if select: + indices = [ headers.index(colname) for colname in select ] + headers = select + + records = [] + for rowno, row in enumerate(rows, 1): + if not row: # Skip rows with no data + continue + + # If specific column indices are selected, pick them out + if select: + row = [ row[index] for index in indices] + + # Apply type conversion to the row + if types: + try: + row = [func(val) for func, val in zip(types, row)] + except ValueError as e: + if not silence_errors: + print(f"Row {rowno}: Couldn't convert {row}") + print(f"Row {rowno}: Reason {e}") + continue + + # Make a dictionary or a tuple + if headers: + record = dict(zip(headers, row)) + else: + record = tuple(row) + records.append(record) + + return records diff --git a/Work/follow.py b/Work/follow.py new file mode 100644 index 000000000..ffa209416 --- /dev/null +++ b/Work/follow.py @@ -0,0 +1,34 @@ +import os +import time + +def follow(filename): + f = open(filename) + f.seek(0, os.SEEK_END) + while True: + line = f.readline() + if line == '': + time.sleep(0.1) + continue + yield line + +def filematch(lines, substr): + lines_1 = lines.split(',') + for line in lines_1: + if substr in line: + yield lines_1 + +if __name__ == '__main__': + import report + portfolio = report.read_portfolio('Data/portfolio.csv') + for line in follow('Data/stocklog.csv'): + ibm = filematch(line,'IBM') + for i in ibm: + print(i) + + fields = line.split(',') + name = fields[0].strip('"') + price = float(fields[1]) + change = float(fields[4]) + if name in portfolio: + print(f'{name:>10s} {price:>10.2f} {change:>10.2f}') + diff --git a/Work/mortgage.py b/Work/mortgage.py index d527314e3..46b19434c 100644 --- a/Work/mortgage.py +++ b/Work/mortgage.py @@ -1,3 +1,32 @@ # mortgage.py # # Exercise 1.7 + +principal = 500000.0 +rate = 0.05 +payment = 2684.11 +total_paid = 0.0 +years = 30 +months = 0 +extra_payment_start_month = 61 +extra_payment_end_month = 108 +extra_payment = 1000 + +while principal > 0: + months += 1 + if(principal * (1+rate/12) - payment < 0): + payment = principal + principal = 0 + else: + principal = principal * (1+rate/12) - payment + total_paid = total_paid + payment + if(months >= extra_payment_start_month and months <= extra_payment_end_month): + if(principal-extra_payment < 0): + break + else: + principal = principal - extra_payment + total_paid = total_paid + extra_payment + print(months, round(total_paid,2), round(principal,2)) + +print('Total paid: ', round(total_paid,2)) +print('Months: ', months) diff --git a/Work/pcost.py b/Work/pcost.py index e68aa20b4..4e1d457f3 100644 --- a/Work/pcost.py +++ b/Work/pcost.py @@ -1,3 +1,25 @@ # pcost.py # # Exercise 1.27 + +# pcost.py + +import report +import stock + +def portfolio_cost(filename): + ''' + Computes the total cost (shares*price) of a portfolio file + ''' + portfolio = report.read_portfolio(filename) + return portfolio.total_cost + +def main(args): + if len(args) != 2: + raise SystemExit('Usage: %s portfoliofile' % args[0]) + filename = args[1] + print('Total cost:', portfolio_cost(filename)) + +if __name__ == '__main__': + import sys + main(sys.argv) diff --git a/Work/portfolio.py b/Work/portfolio.py new file mode 100644 index 000000000..b544998cf --- /dev/null +++ b/Work/portfolio.py @@ -0,0 +1,47 @@ +import fileparse +import stock + +class Portfolio: + + def __init__(self) -> None: + self.holdings = [] + + def __iter__(self): + return self.holdings.__iter__() + + def __len__(self): + return len(self.holdings) + + def __getitem__(self,index): + return self.holdings[index] + + def __contains__(self,name): + return any([s.name == name for s in self.holdings]) + + @property + def total_cost(self): + return sum([s.shares*s.price for s in self.holdings]) + + def append(self, holding): + if not isinstance(holding, stock.Stock): + raise TypeError('Expected a Stock instance') + self.holdings.append(holding) + + @classmethod + def from_csv(cls, lines, **opts): + self = cls() + portdicts = fileparse.parse_csv(lines, + select=['name','shares','price'], + types=[str,int,float], + **opts) + for d in portdicts: + self.append(stock.Stock(**d)) + + return self + + def tabulate_shares(self): + from collections import Counter + total_shares = Counter() + for s in self.holdings: + total_shares[s.name] += s.shares + return total_shares \ No newline at end of file diff --git a/Work/report.py b/Work/report.py index 47d5da7b1..d71303f54 100644 --- a/Work/report.py +++ b/Work/report.py @@ -1,3 +1,76 @@ # report.py # # Exercise 2.4 + +# report.py + +import fileparse +from stock import Stock +from portfolio import Portfolio +import tableformat + +def read_portfolio(filename, **opts): + ''' + Read a stock portfolio file into a list of dictionaries with keys + name, shares, and price. + ''' + with open(filename) as lines: + portDicts = fileparse.parse_csv(lines, + select=['name','shares','price'], + types=[str,int,float], + **opts) + portfolio = [Stock(**d) for d in portDicts] + return Portfolio(portfolio) + +def read_prices(filename): + ''' + Read a CSV file of price data into a dict mapping names to prices. + ''' + with open(filename) as lines: + return dict(fileparse.parse_csv(lines, types=[str,float], has_headers=False)) + +def make_report_data(portfolio,prices): + ''' + Make a list of (name, shares, price, change) tuples given a portfolio list + and prices dictionary. + ''' + rows = [] + for stock in portfolio: + current_price = prices[stock.name] + change = current_price - stock.price + summary = (stock.name, stock.shares, current_price, change) + rows.append(summary) + return rows + +def print_report(reportdata, formatter): + ''' + Print a nicely formated table from a list of (name, shares, price, change) tuples. + ''' + formatter.headings(['Name','Shares','Price','Change']) + for name, shares, price, change in reportdata: + rowdata = [ name, str(shares), f'{price:0.2f}', f'{change:0.2f}' ] + formatter.row(rowdata) + +def portfolio_report(portfoliofile, pricefile, fmt='txt'): + ''' + Make a stock report given portfolio and price data files. + ''' + # Read data files + portfolio = read_portfolio(portfoliofile) + prices = read_prices(pricefile) + + # Create the report data + report = make_report_data(portfolio, prices) + + # Print it out + formatter = tableformat.create_formatter(fmt) + print_report(report, formatter) + +def main(args): + if len(args) != 3: + raise SystemExit('Usage: %s portfile pricefile' % args[0]) + portfolio_report(args[1], args[2], args[3]) + +if __name__ == '__main__': + import sys + main(sys.argv) diff --git a/Work/stock.py b/Work/stock.py new file mode 100644 index 000000000..9f7d8b71a --- /dev/null +++ b/Work/stock.py @@ -0,0 +1,51 @@ +from typing import Type +from typedproperty import typedproperty, String, Integer, Float + +class Stock: + name = String('name') + shares = Integer('shares') + price = Float('price') + + #__slots__ = ('name','_shares','price') + def __init__(self,name,shares,price): + self.name = name + self.shares = shares + self.price = price + + def __repr__(self) -> str: + return f'Stock({self.name!r},{self.shares!r},{self.price!r})' + + @property + def shares(self): + return self._shares + + @shares.setter + def shares(self,value): + if not isinstance(value,int): + raise TypeError('Expected int') + self._shares = value + + @property + def cost(self): + return self.shares * self.price + + def sell(self,numshares): + self.shares -= numshares + +class MyStock(Stock): + def panic(self): + self.sell(self.shares) + +import fileparse +import sys + +def main(args): + global portDicts, portfolio + portDicts = {} + with open(args[1]) as lines: + portDicts = fileparse.parse_csv(lines, select=['name','shares','price'], types=[str,int,float]) + + portfolio = [Stock(d['name'],d['shares'],d['price']) for d in portDicts] + +if __name__ == '__main__': + main(sys.argv) \ No newline at end of file diff --git a/Work/tableformat.py b/Work/tableformat.py new file mode 100644 index 000000000..b4cd8f807 --- /dev/null +++ b/Work/tableformat.py @@ -0,0 +1,80 @@ +class FormatError(Exception): + pass + +class TableFormatter: + def headings(self, headers): + ''' + Emit table headings + ''' + raise NotImplementedError() + + def row(self, rowdata): + ''' + Emit a single row of table data + ''' + raise NotImplementedError() + + +def create_formatter(name): + ''' + Create output format for given input + ''' + if name == 'txt': + return TextTableFormatter() + elif name == 'csv': + return CSVTableFormatter() + elif name == 'html': + return HTMLTableFormatter() + else: + raise FormatError(f'Unknown table format {name}') + +def print_table(objects,columns,formatter): + ''' + Prints output for given attributes + ''' + formatter.headings(columns) + for obj in objects: + rowdata = [ str(getattr(obj,name)) for name in columns ] + formatter.row(rowdata) + + +class TextTableFormatter(TableFormatter): + ''' + Emit a table in plain-text format + ''' + def headings(self, headers): + for h in headers: + print(f'{h:>10s}', end=' ') + print() + print(('-'*10 + ' ')*len(headers)) + + def row(self, rowdata): + for d in rowdata: + print(f'{d:>10s}', end=' ') + print() + +class CSVTableFormatter(TableFormatter): + ''' + Output portfolio data in CSV format + ''' + def headings(self, headers): + print(','.join(headers)) + + def row(self, rowdata): + print(','.join(rowdata)) + +class HTMLTableFormatter(TableFormatter): + ''' + Output portfolio data in HTML format + ''' + def headings(self, headers): + print('', end='') + for h in headers: + print(f'{h}', end='') + print('') + + def row(self, rowdata): + print('', end='') + for d in rowdata: + print(f'{d}', end='') + print('') \ No newline at end of file diff --git a/Work/test.py b/Work/test.py new file mode 100644 index 000000000..58323e728 --- /dev/null +++ b/Work/test.py @@ -0,0 +1,16 @@ +def logged(func): + def wrapper(*args, **kwargs): + print('calling', func.__name__) + return func(*args, **kwargs) + return wrapper + +@logged +def add(x,y): + return x+y + +@logged +def subtract(x,y): + return x-y + +print(add(3,4)) +print(subtract(5,1)) \ No newline at end of file diff --git a/Work/test_stock.py b/Work/test_stock.py new file mode 100644 index 000000000..b038e5cf2 --- /dev/null +++ b/Work/test_stock.py @@ -0,0 +1,26 @@ +import unittest +import stock + +class TestStock(unittest.TestCase): + def test_create(self): + s = stock.Stock('GOOG',100,490.1) + self.assertEqual(s.name, 'GOOG') + self.assertEqual(s.shares, 100) + self.assertEqual(s.price, 490.1) + + def test_cost(self): + s = stock.Stock('GOOG',100,490.1) + self.assertEqual(s.shares*s.price,49010.0) + + def test_sell(self): + s = stock.Stock('GOOG',100,490.1) + s.sell(25) + self.assertEqual(s.shares,75) + + def test_bad_shares(self): + s = stock.Stock('GOOG',100,490.1) + with self.assertRaises(TypeError): + s.shares = '100' + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/Work/ticker.py b/Work/ticker.py new file mode 100644 index 000000000..63664582a --- /dev/null +++ b/Work/ticker.py @@ -0,0 +1,47 @@ +import csv +import report +import tableformat +from follow import follow + + +def convert_types(rows, types): + for row in rows: + yield [func(val) for func,val in zip(types,row)] + +def make_dicts(rows,headers): + for row in rows: + yield dict(zip(headers,row)) + +def select_columns(rows,indices): + for row in rows: + yield [row[index] for index in indices] + +def filter_symbols(rows,names): + for row in rows: + if row['name'] in names: + yield row + +def ticker(portfile,logfile,fmt): + portfolio = report.read_portfolio(portfile) + lines = follow(logfile) + rows = parse_stock_data(lines) + rows = filter_symbols(rows, portfolio) + formatter = tableformat.create_formatter(fmt) + formatter.headings(['Name','Price','Change']) + for row in rows: + formatter.row([ row['name'], f"{row['price']:0.2f}",f"{row['change']:0.2f}" ]) + + +def parse_stock_data(lines): + rows = csv.reader(lines) + rows = select_columns(rows, [0,1,4]) + rows = convert_types(rows, [str,float,float]) + rows = make_dicts(rows, ['name','price','change']) + return rows + +if __name__ == '__main__': + portfolio = report.read_portfolio('Data/portfolio.csv') + rows = parse_stock_data(follow('Data/stocklog.csv')) + rows = filter_symbols(rows, portfolio) + for row in rows: + print(row) \ No newline at end of file diff --git a/Work/timethis.py b/Work/timethis.py new file mode 100644 index 000000000..2a145c521 --- /dev/null +++ b/Work/timethis.py @@ -0,0 +1,16 @@ +import time + +def timethis(func): + def wrapper(*args, **kwargs): + start = time.time() + func(*args, **kwargs) + end = time.time() + print('%s.%s: %f' %(func.__module__, func.__name__, end-start)) + return wrapper + +@timethis +def countdown(n): + while n>0: + n -= 1 + +countdown(10000000) \ No newline at end of file diff --git a/Work/typedproperty.py b/Work/typedproperty.py new file mode 100644 index 000000000..8aa2e566c --- /dev/null +++ b/Work/typedproperty.py @@ -0,0 +1,19 @@ +def typedproperty(name, expected_type): + private_name = '_' + name + @property + def prop(self): + return getattr(self, private_name) + + @prop.setter + def prop(self, value): + if not isinstance(value, expected_type): + raise TypeError(f'Expected {expected_type}') + setattr(self, private_name, value) + + return prop + +String = lambda name: typedproperty(name, str) +Integer = lambda name: typedproperty(name, int) +Float = lambda name: typedproperty(name, float) + + \ No newline at end of file