Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 42 additions & 35 deletions pyalgostrategypool/open_range_breakout_crossover.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ def __init__(self, *args, **kwargs):

# Variables
self.main_order = None
self.order_placed_for_the_day = None
self.current_order_count = None
self.allowed_order_count = None

def initialize(self):
"""
Expand All @@ -38,7 +39,12 @@ def initialize(self):
"""

self.main_order = {}
self.order_placed_for_the_day = {}

# To keep a count of the number of orders for each instrument
self.current_order_count = {}

# Count of number of orders should not exceed the below count
self.allowed_order_count = 2

@staticmethod
def name():
Expand All @@ -61,7 +67,8 @@ def get_decision(self, instrument, decision):
"""
This method returns the entry/exit action based on the crossover value
"""
action = None

crossover_value = 0

# Get OHLC historical data for the instrument
hist_data = self.get_historical_data(instrument)
Expand All @@ -72,24 +79,26 @@ def get_decision(self, instrument, decision):
# Get string value of strategy start time
udc_candle_str = str(self.candle_start_time)

# If latest timestamp is equal to strategy start time
if timestamp_str == udc_candle_str:
latest_high = hist_data['high'].iloc[-1]
latest_close = hist_data['close'].iloc[-1]

# Return action as BUY if crossover is Upwards and decision is Entry, else SELL if decision is EXIT
if self.get_crossover_value(hist_data, latest_high) == 1:
action = ActionConstants.ENTRY_BUY if decision is DecisionConstants.ENTRY_POSITION else ActionConstants.EXIT_SELL
# Get crossover value if decision is ENTRY_POSITION and latest timestamp is equal to strategy start time or decision is EXIT_POSITION
if (decision is DecisionConstants.ENTRY_POSITION and timestamp_str > udc_candle_str) or decision is DecisionConstants.EXIT_POSITION:
crossover_value = self.get_crossover_value(hist_data, latest_close)

# Return action as SELL if crossover is Downwards and decision is Entry, else BUY if decision is EXIT
elif self.get_crossover_value(hist_data, latest_high) == -1:
action = ActionConstants.ENTRY_SELL if decision is DecisionConstants.ENTRY_POSITION else ActionConstants.EXIT_BUY
# Return action as BUY if crossover is Upwards and decision is Entry, else SELL if decision is EXIT
if crossover_value == 1:
action = ActionConstants.ENTRY_BUY if decision is DecisionConstants.ENTRY_POSITION else ActionConstants.EXIT_SELL

# Return action as NO_ACTION if there is no crossover
else:
action = ActionConstants.NO_ACTION
# Return action as SELL if crossover is Downwards and decision is Entry, else BUY if decision is EXIT
elif crossover_value == -1:
action = ActionConstants.ENTRY_SELL if decision is DecisionConstants.ENTRY_POSITION else ActionConstants.EXIT_BUY

# Return action as NO_ACTION if there is no crossover
else:
action = ActionConstants.NO_ACTION
return action

def get_crossover_value(self, hist_data, latest_high):
def get_crossover_value(self, hist_data, latest_close):
"""
This method calculates the crossover using the hist data of the instrument along with the required indicator and returns the crossover value.
"""
Expand All @@ -98,11 +107,10 @@ def get_crossover_value(self, hist_data, latest_high):

# Calculate crossover for the OHLC columns with
columns = ['open', 'high', 'low', 'close']
val_data = [latest_high] * len(hist_data)
val_data = [latest_close] * len(hist_data)
for column in columns:
crossover = self.utils.crossover(hist_data[column], val_data)
if crossover in [1, -1]:

# If crossover is upwards or downwards, stop computing the crossovers
break

Expand Down Expand Up @@ -131,26 +139,24 @@ def strategy_select_instruments_for_entry(self, candle, instruments_bucket):
# Looping over all instruments given by you in the bucket (we can give multiple instruments in the configuration)
for instrument in instruments_bucket:

# Instrument is appended once the main order is exited, this ensures that only one order is placed for the day
if instrument not in self.order_placed_for_the_day:

# Compute various things and get the decision to place an order only if no current order is going on (main order is empty / none)
if self.main_order.get(instrument) is None:
# Initiate the count
if self.current_order_count.get(instrument) is None:
self.current_order_count[instrument] = 0

# Get entry decision
action = self.get_decision(instrument, DecisionConstants.ENTRY_POSITION)
# Compute various things and get the decision to place an order only if no current order is going on (main order is empty / none) and the number of order counts is less than the count
if self.main_order.get(instrument) is None and self.current_order_count.get(instrument) < self.allowed_order_count:

if action is ActionConstants.ENTRY_BUY or (action is ActionConstants.ENTRY_SELL and self.strategy_mode is StrategyMode.INTRADAY):
# Add instrument to the bucket
selected_instruments_bucket.append(instrument)
# Get entry decision
action = self.get_decision(instrument, DecisionConstants.ENTRY_POSITION)

# Add additional info for the instrument
sideband_info_bucket.append({'action': action})
if action is ActionConstants.ENTRY_BUY or (action is ActionConstants.ENTRY_SELL and self.strategy_mode is StrategyMode.INTRADAY):
# Add instrument to the bucket
selected_instruments_bucket.append(instrument)

# If one order has exited already, below message is printed
else:
self.logger.info('Order placed for the day, no more orders will be placed for the remaining day')
# Add additional info for the instrument
sideband_info_bucket.append({'action': action})

# Return the buckets to the core engine
# Return the buckets to the core engine
# Engine will now call strategy_enter_position with each instrument and its additional info one by one
return selected_instruments_bucket, sideband_info_bucket
Expand All @@ -167,12 +173,10 @@ def strategy_enter_position(self, candle, instrument, sideband_info):
# Place buy order
if sideband_info['action'] is ActionConstants.ENTRY_BUY:
self.main_order[instrument] = self.broker.BuyOrderRegular(instrument=instrument, order_code=BrokerOrderCodeConstants.INTRADAY, order_variety=BrokerOrderVarietyConstants.MARKET, quantity=qty)
self.order_placed_for_the_day[instrument] = True

# Place sell order
elif sideband_info['action'] is ActionConstants.ENTRY_SELL:
self.main_order[instrument] = self.broker.SellOrderRegular(instrument=instrument, order_code=BrokerOrderCodeConstants.INTRADAY, order_variety=BrokerOrderVarietyConstants.MARKET, quantity=qty)
self.order_placed_for_the_day[instrument] = True

# Sanity
else:
Expand Down Expand Up @@ -211,6 +215,9 @@ def strategy_select_instruments_for_exit(self, candle, instruments_bucket):
# If order transaction type is buy and current action is sell or order transaction type is sell and current action is buy, then exit the order
if (action is ActionConstants.EXIT_SELL and main_order.order_transaction_type is BrokerOrderTransactionTypeConstants.SELL) or \
(action is ActionConstants.EXIT_BUY and main_order.order_transaction_type is BrokerOrderTransactionTypeConstants.BUY):
# Increment the count if the order is exited
self.current_order_count[instrument] += 1

# Add instrument to the bucket
selected_instruments_bucket.append(instrument)

Expand Down
75 changes: 40 additions & 35 deletions pyalgostrategypool/open_range_breakout_crossover_bracket.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ def __init__(self, *args, **kwargs):

# Variables
self.main_order = None
self.udc_high = None
self.order_placed_for_the_day = None
self.current_order_count = None
self.allowed_order_count = None

def initialize(self):
"""
Expand All @@ -47,8 +47,12 @@ def initialize(self):
"""

self.main_order = {}
self.udc_high = {}
self.order_placed_for_the_day = {}

# To keep a count of the number of orders for each instrument
self.current_order_count = {}

# Count of number of orders should not exceed the below count
self.allowed_order_count = 2

@staticmethod
def name():
Expand All @@ -72,7 +76,7 @@ def get_decision(self, instrument, decision):
This method returns the entry/exit action based on the crossover value
"""

action = None
crossover_value = 0

# Get OHLC historical data for the instrument
hist_data = self.get_historical_data(instrument)
Expand All @@ -83,24 +87,26 @@ def get_decision(self, instrument, decision):
# Get string value of strategy start time
udc_candle_str = str(self.candle_start_time)

# If latest timestamp is equal to strategy start time
if timestamp_str == udc_candle_str:
latest_high = hist_data['high'].iloc[-1]
latest_close = hist_data['close'].iloc[-1]

# Return action as BUY if crossover is Upwards and decision is Entry, else SELL if decision is EXIT
if self.get_crossover_value(hist_data, latest_high) == 1:
action = ActionConstants.ENTRY_BUY if decision is DecisionConstants.ENTRY_POSITION else ActionConstants.EXIT_SELL
# Get crossover value if decision is ENTRY_POSITION and latest timestamp is equal to strategy start time or decision is EXIT_POSITION
if (decision is DecisionConstants.ENTRY_POSITION and timestamp_str > udc_candle_str) or decision is DecisionConstants.EXIT_POSITION:
crossover_value = self.get_crossover_value(hist_data, latest_close)

# Return action as SELL if crossover is Downwards and decision is Entry, else BUY if decision is EXIT
elif self.get_crossover_value(hist_data, latest_high) == -1:
action = ActionConstants.ENTRY_SELL if decision is DecisionConstants.ENTRY_POSITION else ActionConstants.EXIT_BUY
# Return action as BUY if crossover is Upwards and decision is Entry, else SELL if decision is EXIT
if crossover_value == 1:
action = ActionConstants.ENTRY_BUY if decision is DecisionConstants.ENTRY_POSITION else ActionConstants.EXIT_SELL

# Return action as NO_ACTION if there is no crossover
else:
action = ActionConstants.NO_ACTION
# Return action as SELL if crossover is Downwards and decision is Entry, else BUY if decision is EXIT
elif crossover_value == -1:
action = ActionConstants.ENTRY_SELL if decision is DecisionConstants.ENTRY_POSITION else ActionConstants.EXIT_BUY

# Return action as NO_ACTION if there is no crossover
else:
action = ActionConstants.NO_ACTION
return action

def get_crossover_value(self, hist_data, latest_high):
def get_crossover_value(self, hist_data, latest_close):
"""
This method calculates the crossover using the hist data of the instrument along with the required indicator and returns the crossover value.
"""
Expand All @@ -109,11 +115,10 @@ def get_crossover_value(self, hist_data, latest_high):

# Calculate crossover for the OHLC columns with
columns = ['open', 'high', 'low', 'close']
val_data = [latest_high] * len(hist_data)
val_data = [latest_close] * len(hist_data)
for column in columns:
crossover = self.utils.crossover(hist_data[column], val_data)
if crossover in [1, -1]:

# If crossover is upwards or downwards, stop computing the crossovers
break

Expand Down Expand Up @@ -142,25 +147,22 @@ def strategy_select_instruments_for_entry(self, candle, instruments_bucket):
# Looping over all instruments given by you in the bucket (we can give multiple instruments in the configuration)
for instrument in instruments_bucket:

# Instrument is appended once the main order is exited, this ensures that only one order is placed for the day
if instrument not in self.order_placed_for_the_day:

# Compute various things and get the decision to place an order only if no current order is going on (main order is empty / none)
if self.main_order.get(instrument) is None:
# Initiate the count
if self.current_order_count.get(instrument) is None:
self.current_order_count[instrument] = 0

# Get entry decision
action = self.get_decision(instrument, DecisionConstants.ENTRY_POSITION)
# Compute various things and get the decision to place an order only if no current order is going on (main order is empty / none) and the number of order counts is less than the count
if self.main_order.get(instrument) is None and self.current_order_count.get(instrument) < self.allowed_order_count:

if action is ActionConstants.ENTRY_BUY or (action is ActionConstants.ENTRY_SELL and self.strategy_mode is StrategyMode.INTRADAY):
# Add instrument to the bucket
selected_instruments_bucket.append(instrument)
# Get entry decision
action = self.get_decision(instrument, DecisionConstants.ENTRY_POSITION)

# Add additional info for the instrument
sideband_info_bucket.append({'action': action})
if action is ActionConstants.ENTRY_BUY or (action is ActionConstants.ENTRY_SELL and self.strategy_mode is StrategyMode.INTRADAY):
# Add instrument to the bucket
selected_instruments_bucket.append(instrument)

# If one order has exited already, below message is printed
else:
self.logger.info('Order placed for the day, no more orders will be placed for the remaining day')
# Add additional info for the instrument
sideband_info_bucket.append({'action': action})

# Return the buckets to the core engine
# Engine will now call strategy_enter_position with each instrument and its additional info one by one
Expand Down Expand Up @@ -225,6 +227,9 @@ def strategy_select_instruments_for_exit(self, candle, instruments_bucket):
# If order transaction type is buy and current action is sell or order transaction type is sell and current action is buy, then exit the order
if (action is ActionConstants.EXIT_SELL and main_order.order_transaction_type is BrokerOrderTransactionTypeConstants.SELL) or \
(action is ActionConstants.EXIT_BUY and main_order.order_transaction_type is BrokerOrderTransactionTypeConstants.BUY):
# Increment the count if the order is exited
self.current_order_count[instrument] += 1

# Add instrument to the bucket
selected_instruments_bucket.append(instrument)

Expand Down
Loading