|
|
|
|
@ -111,7 +111,7 @@ class Investing(bt.Strategy):
|
|
|
|
|
|
|
|
|
|
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
|
|
|
|
|
self.log("Order Canceled/Margin/Rejected")
|
|
|
|
|
print(order.status, [order.Canceled, order.Margin, order.Rejected])
|
|
|
|
|
print(order, order.status, [order.Canceled, order.Margin, order.Rejected])
|
|
|
|
|
|
|
|
|
|
self.order = None
|
|
|
|
|
|
|
|
|
|
@ -141,9 +141,15 @@ class FormulaInvesting(Investing):
|
|
|
|
|
def notify_timer(self, timer, when, *args):
|
|
|
|
|
super().notify_timer(timer, when, *args)
|
|
|
|
|
self.formula()
|
|
|
|
|
self.prev_value = self.broker.get_value()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class VA(FormulaInvesting):
|
|
|
|
|
"""
|
|
|
|
|
When market is down, buy
|
|
|
|
|
When up, sell. Shitty strategy: https://en.wikipedia.org/wiki/Value_averaging
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def formula(self):
|
|
|
|
|
target_value = (
|
|
|
|
|
min(
|
|
|
|
|
@ -156,28 +162,68 @@ class VA(FormulaInvesting):
|
|
|
|
|
# self.broker.set_cash(self.broker.get_cash() * self.monthly_params["t_rate"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class QVA(VA):
|
|
|
|
|
"""
|
|
|
|
|
Same but quarterly
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def formula(self):
|
|
|
|
|
if not self.months % 3:
|
|
|
|
|
super().formula()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DCA(FormulaInvesting):
|
|
|
|
|
"""
|
|
|
|
|
Buy everything monthly
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def formula(self):
|
|
|
|
|
target_value = self.broker.get_value() - reserve
|
|
|
|
|
self.order_target_value(target=target_value)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class QVA(VA):
|
|
|
|
|
class QDCA(DCA):
|
|
|
|
|
"""
|
|
|
|
|
Buy everything quarterly
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def formula(self):
|
|
|
|
|
if not self.months % 3:
|
|
|
|
|
super().formula()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class QDCA(DCA):
|
|
|
|
|
def formula(self):
|
|
|
|
|
if not self.months % 3:
|
|
|
|
|
super().formula()
|
|
|
|
|
class EDCA(Investing):
|
|
|
|
|
"""
|
|
|
|
|
When market is down, BUY THE DIP
|
|
|
|
|
When up, leave some cash
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
self.prev_value = 0
|
|
|
|
|
|
|
|
|
|
def notify_timer(self, timer, when, *args):
|
|
|
|
|
self.months += 1
|
|
|
|
|
|
|
|
|
|
if self.prev_value >= self.broker.get_value():
|
|
|
|
|
self.broker.add_cash(1.1 * self.monthly_cash)
|
|
|
|
|
else:
|
|
|
|
|
self.broker.add_cash(0.9 * self.monthly_cash)
|
|
|
|
|
|
|
|
|
|
target_value = self.broker.get_value()
|
|
|
|
|
self.order_target_value(target=target_value - reserve)
|
|
|
|
|
|
|
|
|
|
self.prev_value = self.broker.get_value()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SmaCross(Investing):
|
|
|
|
|
"""
|
|
|
|
|
Buy when fast moving average crosses slow upwards
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
params = dict(
|
|
|
|
|
pfast=50, # period for the fast moving average
|
|
|
|
|
pslow=200, # period for the slow moving average
|
|
|
|
|
pfast=8, # period for the fast moving average
|
|
|
|
|
pslow=17, # period for the slow moving average
|
|
|
|
|
)
|
|
|
|
|
# list of parameters which are configurable for the strategy
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
@ -187,19 +233,7 @@ class SmaCross(Investing):
|
|
|
|
|
self.crossover = bt.ind.CrossOver(sma1, sma2) # crossover signal
|
|
|
|
|
|
|
|
|
|
def next(self):
|
|
|
|
|
if not self.position: # not in the market
|
|
|
|
|
if self.crossover > 0: # if fast crosses slow to the upside
|
|
|
|
|
self.order_target_value(target=self.broker.get_cash()) # enter long
|
|
|
|
|
|
|
|
|
|
elif self.crossover < 0: # in the market & cross to the downside
|
|
|
|
|
self.close() # close long position
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SmaVA(SmaCross):
|
|
|
|
|
def next(self):
|
|
|
|
|
if not self.position: # not in the market
|
|
|
|
|
if self.crossover > 0: # if fast crosses slow to the upside
|
|
|
|
|
self.order_target_value(target=self.broker.get_cash()) # enter long
|
|
|
|
|
|
|
|
|
|
elif self.crossover < 0: # in the market & cross to the downside
|
|
|
|
|
self.order_target_value(target=self.broker.get_value() / 2) # close half
|
|
|
|
|
self.order_target_value(
|
|
|
|
|
target=self.broker.get_value() - reserve
|
|
|
|
|
) # enter long
|
|
|
|
|
|