from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import RSI
from quantopian.pipeline.factors import SimpleMovingAverage
from quantopian.pipeline.factors import AverageDollarVolume
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
import talib
import pandas as pd
import numpy as np
from scipy import stats
def initialize(context):
pipe = Pipeline()
attach_pipeline(pipe, name='my_pipeline')
SMA_20 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=20)
price = USEquityPricing.close.latest
price_above_SMA20 = (price >= SMA_20)
volume = USEquityPricing.volume.latest
volume_1m = (volume > 1000000)
pipe.add(SMA_20, 'SMA_20')
pipe.set_screen(volume_1m & price_above_SMA20)
context.SL_Manager = StopLoss_Manager()
schedule_function(order_picks, date_rules.every_day(), time_rules.market_open())
schedule_function(context.SL_Manager.manage_orders, date_rules.every_day(), time_rules.market_open())
def before_trading_start(context, data):
# Access results using the name passed to attach_pipeline.
results = pipeline_output('my_pipeline')
print(results.head(40))
# Store pipeline results for use by the rest of the algorithm.
context.stocks = results
def order_picks(context,data):
context.total_cost_per_trade = 500
actual_cash = (context.portfolio.portfolio_value - context.portfolio.positions_value)
available_cash = max(actual_cash, 0)
qty_of_positions_to_open = available_cash // context.total_cost_per_trade
positions_to_open = context.stocks.head(qty_of_positions_to_open).index
for stock in positions_to_open:
if data.can_trade(stock):
order_value(stock, context.total_cost_per_trade)
for stock in context.portfolio.positions.keys():
if stock not in context.stocks.index:
if data.can_trade(stock):
order_target_percent(stock,0)
class StopLoss_Manager:
"""
Class to manage to stop-orders for any open position or open (non-stop)-order. This will be done for long- and short-positions.
Parameters:
pct_init (optional),
pct_trail (optional),
(a detailed description can be found in the set_params function)
Example Usage:
context.SL = StopLoss_Manager(pct_init=0.005, pct_trail=0.03)
context.SL.manage_orders(context, data)
"""
def set_params(self, **params):
"""
Set values of parameters:
pct_init (optional float between 0 and 1):
- After opening a new position, this value
is the percentage above or below price,
where the first stop will be place.
pct_trail (optional float between 0 and 1):
- For any existing position the price of the stop
will be trailed by this percentage.
"""
additionals = set(params.keys()).difference(set(self.params.keys()))
if len(additionals)>1:
log.warn('Got additional parameter, which will be ignored!')
del params[additionals]
self.params.update(params)
def manage_orders(self, context, data):
"""
This will:
- identify any open positions and orders with no stop (short and long)
- create new stop levels
- manage existing stop levels
- create StopOrders with appropriate price and amount
"""
self._refresh_amounts(context)
for sec in self.stops.index:
cancel_order(self.stops['id'][sec])
if not data.can_trade(sec): continue
if self._np.isnan(self.stops['price'][sec]):
stop = (1-self.params['pct_init'])*data.current(sec, 'close')
else:
o = self._np.sign(self.stops['amount'][sec])
new_stop = (1-o*self.params['pct_trail'])*data.current(sec, 'close')
stop = o*max(o*self.stops['price'][sec], o*new_stop)
self.stops.loc[sec, 'price'] = stop
self.stops.loc[sec, 'id'] = order(sec, -self.stops['amount'][sec], style=StopOrder(stop))
def __init__(self, **params):
"""
Creatin new StopLoss-Manager object.
"""
self._import()
self.params = {'pct_init': 0.07, 'pct_trail': 0.07}
self.stops = self._pd.DataFrame(columns=['amount', 'price', 'id'])
self.set_params(**params)
def _refresh_amounts(self, context):
"""
Identify open positions and orders.
"""
# Reset position amounts
self.stops.loc[:, 'amount'] = 0.
# Get open orders and remember amounts for any order with no defined stop.
open_orders = get_open_orders()
new_amounts = []
for sec in open_orders:
for order in open_orders[sec]:
if order.stop is None:
new_amounts.append((sec, order.amount))
# Get amounts from portfolio positions.
for sec in context.portfolio.positions:
new_amounts.append((sec, context.portfolio.positions[sec].amount))
# Sum amounts up.
for (sec, amount) in new_amounts:
if not sec in self.stops.index:
self.stops.loc[sec, 'amount'] = amount
else:
self.stops.loc[sec, 'amount'] = +amount
# Drop securities, with no position/order any more.
drop = self.stops['amount'] == 0.
self.stops.drop(self.stops.index[drop], inplace=True)
def _import(self):
"""
Import of needed packages.
"""
import numpy
self._np = numpy
import pandas
self._pd = pandas