|
5 | 5 | import logging |
6 | 6 |
|
7 | 7 | from datetime import datetime |
| 8 | +from collections import defaultdict |
8 | 9 |
|
9 | 10 | from . import database |
10 | 11 | from . import api |
| 12 | +from . import web |
11 | 13 | from . import cache |
12 | 14 | from . import errors |
13 | 15 |
|
@@ -872,6 +874,122 @@ def sort_and_format(filer_ciks): |
872 | 874 | raise KeyError |
873 | 875 |
|
874 | 876 |
|
| 877 | +def analyze_changes(cik): |
| 878 | + |
| 879 | + pipeline = [ |
| 880 | + {"$match": {"cik": cik, "form": {"$in": database.holding_forms}}}, |
| 881 | + { |
| 882 | + "$project": { |
| 883 | + "access_number": 1, |
| 884 | + "stocks": {"$objectToArray": "$stocks"}, |
| 885 | + } |
| 886 | + }, |
| 887 | + {"$project": {"access_number": 1, "stock": "$stocks.v"}}, |
| 888 | + {"$unwind": "$stock"}, |
| 889 | + { |
| 890 | + "$project": { |
| 891 | + "access_number": 1, |
| 892 | + "stock.cusip": 1, |
| 893 | + "stock.shares_held": 1, |
| 894 | + "stock.market_value": 1, |
| 895 | + } |
| 896 | + }, |
| 897 | + { |
| 898 | + "$group": { |
| 899 | + "_id": "$access_number", |
| 900 | + "access_number": {"$first": "$access_number"}, |
| 901 | + "stocks": {"$push": "$stock"}, |
| 902 | + } |
| 903 | + }, |
| 904 | + { |
| 905 | + "$set": { |
| 906 | + "access_number": "$_id", |
| 907 | + } |
| 908 | + }, |
| 909 | + { |
| 910 | + "$project": { |
| 911 | + "_id": 0, |
| 912 | + "access_number": 1, |
| 913 | + "stocks": { |
| 914 | + "$arrayToObject": { |
| 915 | + "$map": { |
| 916 | + "input": "$stocks", |
| 917 | + "as": "stock", |
| 918 | + "in": {"k": "$$stock.cusip", "v": "$$stock"}, |
| 919 | + } |
| 920 | + } |
| 921 | + }, |
| 922 | + } |
| 923 | + }, |
| 924 | + ] |
| 925 | + filings_reports = [f["access"] for f in web.check_forms(cik)] |
| 926 | + filings_list = [f for f in database.search_filings(pipeline)] |
| 927 | + |
| 928 | + changes_list = [] |
| 929 | + for next_filing in filings_list: |
| 930 | + |
| 931 | + next_access = next_filing["access_number"] |
| 932 | + next_index = filings_reports.index(next_access) |
| 933 | + |
| 934 | + prev_index = next_index + 1 if next_index + 1 < len(filings_reports) else None |
| 935 | + if prev_index is None: |
| 936 | + changes_list.append( |
| 937 | + { |
| 938 | + "access_number": next_access, |
| 939 | + "changes": [], |
| 940 | + } |
| 941 | + ) |
| 942 | + continue |
| 943 | + prev_access = filings_reports[prev_index] |
| 944 | + prev_filing = next( |
| 945 | + (f for f in filings_list if f["access_number"] == prev_access), |
| 946 | + None, |
| 947 | + ) |
| 948 | + |
| 949 | + if not prev_filing: |
| 950 | + continue |
| 951 | + |
| 952 | + next_stocks = next_filing.get("stocks", {}) |
| 953 | + prev_stocks = prev_filing.get("stocks", {}) |
| 954 | + |
| 955 | + if not next_stocks or not prev_stocks: |
| 956 | + continue |
| 957 | + |
| 958 | + change = defaultdict(lambda: {"shares": {}, "value": {}}) |
| 959 | + for cusip in next_stocks: |
| 960 | + next_stock = next_stocks[cusip] |
| 961 | + prev_stock = prev_stocks.get(cusip, None) |
| 962 | + |
| 963 | + next_shares = next_stock["shares_held"] |
| 964 | + prev_shares = prev_stock["shares_held"] if prev_stock else 0 |
| 965 | + if next_shares != prev_shares: |
| 966 | + change[cusip]["shares"]["amount"] = abs(next_shares - prev_shares) |
| 967 | + change[cusip]["shares"]["type"] = ( |
| 968 | + "buy" if next_shares > prev_shares else "sell" |
| 969 | + ) |
| 970 | + |
| 971 | + next_value = next_stock["market_value"] |
| 972 | + prev_value = prev_stock["market_value"] if prev_stock else 0 |
| 973 | + if next_value != prev_value: |
| 974 | + change[cusip]["value"]["amount"] = abs(next_value - prev_value) |
| 975 | + change[cusip]["value"]["type"] = ( |
| 976 | + "buy" if next_value > prev_value else "sell" |
| 977 | + ) |
| 978 | + change = dict(change) |
| 979 | + |
| 980 | + database.edit_filing( |
| 981 | + {"cik": cik, "access_number": next_access}, {"$set": {"changes": change}} |
| 982 | + ) |
| 983 | + changes_list.append( |
| 984 | + { |
| 985 | + "access_number": next_access, |
| 986 | + "changes": change, |
| 987 | + } |
| 988 | + ) |
| 989 | + |
| 990 | + return changes_list |
| 991 | + |
| 992 | + |
875 | 993 | # Really janky/inefficient |
876 | 994 |
|
877 | 995 |
|
|
0 commit comments