import quantopian.optimize as opt
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.filters import QTradableStocksUS
from quantopian.pipeline.domain import US_EQUITIES
from quantopian.research import run_pipeline
# Form 3 transactions
from quantopian.pipeline.data.factset.ownership import Form3AggregatedTrades
# Form 4 and Form 5 transactions
from quantopian.pipeline.data.factset.ownership import Form4and5AggregatedTrades
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
qtu = QTradableStocksUS()
# Slice the Form3AggregatedTrades DataSetFamily and Form4and5AggregatedTrades
# DataSetFamily into DataSets. Here, insider_txns_form3_90d is a DataSet
# containing insider transaction data for Form 3 over the past 90 calendar
# days, and insider_txns_form4and5_90d is a DataSet containing insider
# transaction data for Forms 4 and 5 over the past 90 calendar days. We only
# include non-derivative ownership (derivative_holdings is False).
insider_txns_form3_90d = Form3AggregatedTrades.slice(False, 90)
insider_txns_form4and5_90d = Form4and5AggregatedTrades.slice(False, 90)
# From each DataSet, extract the number of unique buyers and unique sellers.
# We do not need to include unique sellers using Form 3, because Form 3 is
# an initial ownership filing, and so there are no sellers using Form 3.
unique_filers_form3_90d = insider_txns_form3_90d.num_unique_filers.latest
unique_buyers_form4and5_90d = insider_txns_form4and5_90d.num_unique_buyers.latest
unique_sellers_form4and5_90d = insider_txns_form4and5_90d.num_unique_sellers.latest
# Sum the unique buyers from each form together.
unique_buyers_90d = unique_filers_form3_90d + unique_buyers_form4and5_90d
unique_sellers_90d = unique_sellers_form4and5_90d
# Compute the fractions of insiders buying and selling.
frac_insiders_buying_90d = unique_buyers_90d / (unique_buyers_90d + unique_sellers_90d)
frac_insiders_selling_90d = unique_sellers_90d / (unique_buyers_90d + unique_sellers_90d)
# compute factor as buying-selling rank zscores
alpha_factor = frac_insiders_buying_90d - frac_insiders_selling_90d
screen = qtu & ~alpha_factor.isnull() & alpha_factor.isfinite()
alpha_factor, screen
# Winsorize to remove extreme outliers
alpha_winsorized = alpha_factor.winsorize(min_percentile=0.02,
max_percentile=0.98,
mask=screen)
# Zscore and rank to get long and short (positive and negative) alphas to use as weights
alpha_rank = alpha_winsorized.rank().zscore()
pipe = Pipeline(columns={'alpha_factor': alpha_rank},
screen=screen, domain=US_EQUITIES)
results = run_pipeline(pipe, start_date='01-01-2014',end_date='09-01-2017')
print(results.head())
weights = results.alpha_factor / results.alpha_factor.abs().sum()
weights[:5]
insider_txns_form4and5_90d.asof_date??
x = Form3AggregatedTrades.slice(True,90)
z = Form4and5AggregatedTrades.slice(True,90)
y = x.num_unique_filers.latest
a = z.num_unique_buyers.latest
form_winsorized = a.winsorize(min_percentile = 0.02,
max_percentile = 0.98,
mask= screen)
alpha_rank = form_winsorized.rank().zscore()
pipe = Pipeline(columns = {'Form3' : alpha_rank},
screen = screen, domain = US_EQUITIES)
results = run_pipeline(pipe, start_date='01-01-2014',end_date='01-04-2017')
results.head()
weights = results.Form3 / results.Form3.abs().sum()
weights
close_price = USEquityPricing.close.latest
from quantopian.pipeline.filters import Q500US
universe = Q500US()
pipe = Pipeline(columns = {'price': close_price}, screen = universe)
run_pipeline(pipe, start_date='01-01-2014',end_date='01-06-2017')
from quantopian.pipeline.factors import CustomFactor
wl = 252
class Momentum(CustomFactor):
""" Conventional Momentum factor """
inputs = [USEquityPricing.close]
window_length = wl
def compute(self, today, assets, out, prices):
out[:] = (prices[-21] - prices[-252])/prices[-252]
close_price = USEquityPricing.close.latest
from quantopian.pipeline.filters import Q500US
universe = QTradableStocksUS()
def make_pipeline():
pipe = Pipeline()
pipe.add(Momentum(mask=universe), 'momentum')
pipe.set_screen(universe)
return pipe
pipe = make_pipeline()
results = run_pipeline(pipe, start_date='01-05-2020',end_date='01-05-2020')
results.head()
results.momentum.sort_values(ascending = False).nlargest(100)
from quantopian.pipeline import CustomFactor
class WeekOverWeekDifference(CustomFactor):
window_length = 63
def compute(self, today, assets, out, value):
out[:] = value[0] - value[-1]
#unique_filers_form3_90d = insider_txns_form3_90d.num_unique_filers.latest
unique_buyers_form4and5_90 = insider_txns_form4and5_90d.num_unique_buyers
unique_sellers_form4and5_90 = insider_txns_form4and5_90d.num_unique_sellers
unique_buyers_week_diff = WeekOverWeekDifference(inputs = [unique_buyers_form4and5_90])
unique_sellers_week_diff = WeekOverWeekDifference(inputs = [unique_sellers_form4and5_90])
pipe = Pipeline(columns={'unique_filers_form3_90d': unique_filers_form3_90d,
'unique_buyers_form4and5_90d': unique_buyers_form4and5_90d,
'unique_sellers_form4and5_90d': unique_sellers_form4and5_90d,
'insider_buyers_week_diff': unique_buyers_week_diff,
'insider_sellers_week_diff': unique_sellers_week_diff},
screen=screen, domain=US_EQUITIES)
df = run_pipeline(pipe, start_date='10-01-2010',end_date='10-01-2017')
df.head()
df_ndsn = df[df.index.get_level_values(1) == symbols('NDSN')]
df_ndsn.head()
plt.plot(df_ndsn.index.get_level_values(0),(df_ndsn['unique_buyers_form4and5_90d']+ df_ndsn['unique_sellers_form4and5_90d']))
plt.title('Count of Microsoft insiders trading')
plt.ylabel('Count of Microsoft insiders trading')
plt.xlabel('Date')
plt.plot(df_ndsn['insider_buyers_week_diff'])