def main(): parser = argparse.ArgumentParser( description= "Parses output from TabulaPDF. You must supply both a 1099b and\n" "corresponding statements with the same lots. This script will\n" "match lots so that you get the correct purchase date and basis\n" "for all lots on the 1099b.\n" "The output is a clean csv file that can be fed into the wash sale\n" "calculator.\n" "WARNING: Doesn't handle the case where you sold part of a lot.") parser.add_argument('--in1099b', help="1099b input file as output from TabulaPDF") parser.add_argument('--statements', help="statement input files output from TabulaPDF", nargs='+') parser.add_argument('-o', '--out_file') parsed = parser.parse_args() lots = [] print parsed.statements for csvfile in parsed.statements: print 'parsing statement', csvfile lots.extend(parse_schwab_statement(open(csvfile))) lot.print_lots(lots) lots = remove_sold_buys(lots) from1099 = parse_schwab_1099b(open(parsed.in1099b)) lot.print_lots(from1099) from1099 = match_lots_to_1099(lots, from1099) print "1099b final:" for outlot in from1099: print outlot lot.save_lots(from1099, parsed.out_file)
def main(): parser = argparse.ArgumentParser() parser.add_argument('-o', '--out_file') parser.add_argument('-w', '--do_wash', metavar='in_file') parser.add_argument('-q', '--quiet', action="store_true") parser.add_argument('-m', '--merge_split_lots', action="store_true", help='''Any split lots are merged back together at end. This makes it easier to match the output to the input lots, but can cause the buy-dates to be slightly incorrect since a lot can only have a single buy date. In this mode, some wash sale lots may have a loss that is greater than the adjustment amount, instead of being identical, i.e., only part of the loss in the lot is actually a wash sale. This is expected in this mode..''') parser.add_argument( '-r', '--adjust_for_dollar_rounding', action="store_true", help='''Some tax software packages will round the basis, proceeds and adjustment to calculate the total loss (or profit). This can cause problems for wash sales which instead of having a loss of $0 may now have a profit of $1, which results in a warning about a wash sale lot with a profit. Fix this by slightly modifying the adjustment amount so that the final loss will be $0 in such cases. It is safe to use this option with the merge_split_lots option.''') parsed = parser.parse_args() if parsed.do_wash: lots = lot.load_lots(open(parsed.do_wash)) lot.print_lots(lots, False) if parsed.quiet: logger = progress_logger.NullLogger() else: logger = progress_logger.TermLogger() out = perform_wash(lots, logger) # merge split lots back together, if asked. if parsed.merge_split_lots: out = lot.merge_split_lots(out) # make the adjustment safe for whole-dollar rounding arithmentic if parsed.adjust_for_dollar_rounding: lot.adjust_for_dollar_rounding(out) # readable text output print 'output:' lot.print_lots(out, merged=parsed.merge_split_lots, rounded_dollars=parsed.adjust_for_dollar_rounding) # CSV text output if parsed.out_file: print 'Saving final lots to', parsed.out_file lot.save_lots(out, open(parsed.out_file, 'w'))
def main(): parser = argparse.ArgumentParser() parser.add_argument('-o', '--out_file') parser.add_argument('-w', '--do_wash', metavar='in_file') parser.add_argument('-q', '--quiet', action="store_true") parser.add_argument('-m', '--merge_split_lots', action="store_true", help='''Any split lots are merged back together at end. This makes it easier to match the output to the input lots, but can cause the buy-dates to be slightly incorrect since a lot can only have a single buy date. In this mode, some wash sale lots may have a loss that is greater than the adjustment amount, instead of being identical, i.e., only part of the loss in the lot is actually a wash sale. This is expected in this mode..''') parser.add_argument('-r', '--adjust_for_dollar_rounding', action="store_true", help='''Some tax software packages will round the basis, proceeds and adjustment to calculate the total loss (or profit). This can cause problems for wash sales which instead of having a loss of $0 may now have a profit of $1, which results in a warning about a wash sale lot with a profit. Fix this by slightly modifying the adjustment amount so that the final loss will be $0 in such cases. It is safe to use this option with the merge_split_lots option.''') parsed = parser.parse_args() if parsed.do_wash: lots = lot.load_lots(open(parsed.do_wash)) lot.print_lots(lots, False) if parsed.quiet: logger = progress_logger.NullLogger() else: logger = progress_logger.TermLogger() out = perform_wash(lots, logger) # merge split lots back together, if asked. if parsed.merge_split_lots: out = lot.merge_split_lots(out) # make the adjustment safe for whole-dollar rounding arithmentic if parsed.adjust_for_dollar_rounding: lot.adjust_for_dollar_rounding(out) # readable text output print 'output:' lot.print_lots(out, merged=parsed.merge_split_lots, rounded_dollars=parsed.adjust_for_dollar_rounding) # CSV text output if parsed.out_file: print 'Saving final lots to', parsed.out_file lot.save_lots(out, open(parsed.out_file, 'w'))
def main(): parser = argparse.ArgumentParser() parser.add_argument('-o', '--out_file') parser.add_argument('-w', '--do_wash', metavar='in_file') parser.add_argument('-q', '--quiet', action="store_true") parsed = parser.parse_args() if parsed.do_wash: lots = lot.load_lots(parsed.do_wash) lot.print_lots(lots) if parsed.quiet: logger = progress_logger.NullLogger() else: logger = progress_logger.TermLogger() out = perform_wash(lots, logger) print 'output:' lot.print_lots(out) if parsed.out_file: print 'Saving final lots to', parsed.out_file lot.save_lots(out, parsed.out_file)
def run_test(input_csv, expected_out_csv, merge_split_lots=False, rounded_dollars=False): lots = lot.load_lots(open(input_csv)) out = wash.perform_wash(lots, progress_logger.NullLogger()) out.sort(cmp=wash.cmp_by_buy_date) # merge split lots back together, if asked. if merge_split_lots: out = lot.merge_split_lots(out) # make the adjustment safe for whole-dollar rounding arithmentic if rounded_dollars: lot.adjust_for_dollar_rounding(out) # Sort both out and expected the same way, so we can compare them. out.sort(cmp=wash.cmp_by_buy_date) out_csv = StringIO.StringIO() lot.save_lots(out, out_csv) expected = lot.load_lots(open(expected_out_csv)) expected.sort(cmp=wash.cmp_by_buy_date) expected_csv = StringIO.StringIO() lot.save_lots(expected, expected_csv) # Report pass/fail mods = "(merged split-lots) " if merge_split_lots else "" mods += "(safe for whole-dollar arithmetic) " if rounded_dollars else "" # lot.__eq__ compares all members, including original_form_position # and will also include any future internal data members. So, to compare # the test vs expected, we use the output CSV file for both, which should # be invariant. if out_csv.getvalue() != expected_csv.getvalue(): print "****\n%sTest failed: %s" % (mods, input_csv) print "Got result:" print out_csv.getvalue() print "\nExpected output:", expected_out_csv print expected_csv.getvalue() else: print "%sTest passed: %s" % (mods, input_csv)