def test_add_trade_buy_sell_flat(self): pos = TradePositionFIFO() pos.add_trade(Trade(datetime(2020, 3, 25), 'DUMMY', 'Buy', 100, 10)) pnl = pos.add_trade( Trade(datetime(2020, 3, 25), 'DUMMY', 'Sell', 100, 12)) self.assertEqual(200, pnl) self.assertEqual(0, len(pos.trades))
def test_add_trade_buy_sell_flip(self): pos = TradePositionFIFO() pos.add_trade(Trade(datetime(2020, 3, 25), 'DUMMY', 'Buy', 50, 10)) pos.add_trade(Trade(datetime(2020, 3, 25), 'DUMMY', 'Sell', 80, 12)) self.assertEqual(1, len(pos.trades)) self.assertEqual('Sell', pos.trades[0].way) self.assertEqual(30, sum([t.quantity for t in pos.trades]))
def test_new_negative_quantity(self): try: Trade(datetime(2020, 3, 25), 'DUMMY', 'Buy', -100, 10) except ValueError: pass else: self.fail('ValueError not raised')
def test_new_invalid_way(self): try: Trade(datetime(2020, 3, 25), 'DUMMY', 'XXX', 100, 10) except ValueError: pass else: self.fail('ValueError not raised')
def buy(self, main_amount, amount, profit_percent): if (self.main_balance - main_amount) >= self.currency.min_main: log( 'Buying ' + str(amount) + ' ' + self.currency_alt + ' at a rate of ' + str(self.lowest_ask) + ' ' + self.currency_main, True) order = Trade().buy(self.poloniex, self.lowest_ask, amount, self.currency.currency_pair) if order is not None: assert isinstance(order, Order) log( str(datetime.now()) + ' - Bought ' + str(order.amount) + ' ' + self.currency_alt + ' for ' + str(order.total) + ' ' + self.currency_main + ' at ' + str(order.rate) + ' ' + self.currency_main + ' for a ' + "{0:.2f}".format(profit_percent * 100) + '% profit', True) return TradeResult.success elif self.last_trade_type != TradeResult.failure: if self.last_trade_type != TradeResult.failure: log( 'Not enough funds in your ' + self.currency_main + ' account! You need at least ' + str(self.currency.min_main) + ' ' + self.currency_main, True) return TradeResult.failure
def sell(self, amount, profit_percent): if (self.alt_balance - amount) >= self.currency.min_alt and amount > 0: log( 'Selling ' + str(amount) + ' ' + self.currency_alt + ' at a rate of ' + str(self.highest_bid) + ' ' + self.currency_main, True) order = Trade().sell(self.poloniex, self.highest_bid, amount, self.currency.currency_pair) if order is not None: assert isinstance(order, Order) log( str(datetime.now()) + ' - Sold ' + str(order.amount) + ' ' + self.currency_alt + ' for ' + str(order.total) + ' ' + self.currency_main + ' at ' + str(order.rate) + ' ' + self.currency_main + ' for a ' + "{0:.2f}".format(profit_percent * 100) + '% profit', True) return TradeResult.success elif self.last_trade_type != TradeResult.failure: if self.last_trade_type != TradeResult.failure: log( 'Not enough funds in your ' + self.currency_alt + ' account! You need at least ' + str(self.currency.min_alt) + ' ' + self.currency_alt, True) return TradeResult.failure
def open(candle, fb, symbol, trades, params): trade = None allowed_to_buy = False allowed_to_sell = False has_buy_signal = False has_sell_signal = False open_reason = None if True: # TAIL if params.get('open_TAIL', False): bs = 0.01 if candle.body_size() == 0 else candle.body_size() if candle.low_tail()/bs > 0.2: has_buy_signal = True open_reason = 'TAIL_BUY' elif candle.high_tail()/bs > 0.2: has_sell_signal = True open_reason = 'TAIL_SELL' if fb.pointer > 5: # BREAKUP if params.get('open_BREAK', False): f = fb.last(symbol, 5, figure=True) if f.is_breakup(): has_buy_signal = True open_reason = 'BREAKUP_BUY' if f.is_breakdown(): has_sell_signal = True open_reason = 'BREAKDOWN_SELL' #HAMMER if params.get('open_HAMMER', False): f = fb.last(symbol, 3, figure=True) if f.summary().is_hammer() or f.summary(last=2).is_hammer(): has_buy_signal = True open_reason = 'HAMMER_BUY' elif f.summary().is_shooting_star() or f.summary(last=2).is_shooting_star(): has_sell_signal = True open_reason = "S_STAR_SELL" #FRACTAL if params.get('open_FRACTAL', False): f = fb.last(symbol, 5, figure=True) if f.is_bottom_fractal(): has_buy_signal = True open_reason = 'FRAC_BUY' elif f.is_top_fractal(): has_sell_signal = True open_reason = 'FRAC_SELL' if params.get('open_C2', False): if CCI(fb.last(symbol, 2)) > CCI(fb.last(symbol, 2, -1)): has_buy_signal = True open_reason = 'C2_BUY' elif CCI(fb.last(symbol, 2)) > CCI(fb.last(symbol, 2, -1)): has_buy_signal = True open_reason = 'C2_SELL' filter_passed = True if params.get('use_FILTERS', False): filter_passed = False max_per = params.get('f_max_per', 250) th = params.get('f_max_th', 0.8) if fb.pointer > max_per: m = max(bar['high'] for bar in fb.last(symbol, max_per)) if candle.close_price > m*th: filter_passed = True if filter_passed and (has_buy_signal or has_sell_signal): tp_value = candle.close_price*params.get('rel_tp_k', 0.2) if has_buy_signal: #if ts['open_long'] > ts['open_short'] or ts['open'] == 0: allowed_to_buy = True # else: # if ts['open_profit'] > -0.5: # PARAMS! # if params.get('use_FLIP', False): # close_all(trades, candle, 'FLIP') # allowed_to_sell = True if has_sell_signal: # if ts['open_long'] < ts['open_short'] or ts['open'] == 0: allowed_to_sell = True # else: # if ts['open_profit'] > -0.5: # if params.get('use_FLIP', False): # close_all(trades, candle, 'FLIP') # allowed_to_buy = True if allowed_to_buy and allowed_to_sell: allowed_to_buy = False allowed_to_sell = False if allowed_to_buy: trade = Trade() trade.open_trade(symbol,'BUY', candle, candle.close_price, candle.low_price*params.get('init_sl_k', 0.98), candle.close_price + tp_value, open_reason) if allowed_to_sell and params.get('trade_short', False): trade = Trade() trade.open_trade(symbol,'SELL', candle, candle.close_price, candle.high_price*(2-params.get('init_sl_k', 0.98)), candle.close_price - tp_value, open_reason) return trade
def test_add_trade_unrealized_pnl(self): pos = TradePositionFIFO() pos.add_trade(Trade(datetime(2020, 3, 25), 'DUMMY', 'Buy', 100, 10)) pos.add_trade(Trade(datetime(2020, 3, 25), 'DUMMY', 'Buy', 50, 11)) self.assertEqual(250, pos.unrealized_pnl(12))
def test_new(self): t = Trade(datetime(2020, 3, 25), 'DUMMY', 'Buy', 100, 10) self.assertIsInstance(t, Trade)
def open(cc, f, symbol, trades, params): trade = None #ts = trade_stats(trades) allowed_to_buy = False has_buy_signal = False open_reason = None if True: # TAIL if params.get('open_TAIL', False): bs = 0.01 if cc.body_size() == 0 else cc.body_size() if cc.low_tail() / bs > 0.2: has_buy_signal = True open_reason = 'TAIL_BUY' if f.pointer > 50: # BREAKUP if params.get('open_BREAK', False): ff = f.last(symbol, 5, figure=True) if ff.is_breakup(): has_buy_signal = True open_reason = 'BREAKUP_BUY' #HAMMER if params.get('open_HAMMER', False): ff = f.last(symbol, 3, figure=True) if ff.summary().is_hammer() or ff.summary(last=2).is_hammer(): has_buy_signal = True open_reason = 'HAMMER_BUY' #DOUBLE HAMMER if params.get('open_DOUBLE_HAMMER', False): pf = params.get('dh_fast', 2) ps = params.get('dh_slow', 20) if f.last(symbol, pf, figure=True).summary().is_hammer() and f.last( symbol, ps, figure=True).summary().is_hammer(): has_buy_signal = True open_reason = 'DOUBLE_HAMMER' #FRACTAL if params.get('open_FRACTAL', False): ff = f.last(symbol, 5, figure=True) if ff.is_bottom_fractal(): has_buy_signal = True open_reason = 'FRAC_BUY' #C2 if params.get('open_C2', False): if CCI(f.last(symbol, 2)) > CCI(f.last(symbol, 2, -1)): has_buy_signal = True open_reason = 'C2_BUY' passed_filters = [] if params.get('use_HIGH_FILTER', False): high_filter_passed = 0 max_per = params.get('hf_max_per', 250) th = params.get('hf_max_th', 0.8) if f.pointer > max_per: m = max(bar['high'] for bar in f.last(symbol, max_per)) if cc.close_price > m * th: high_filter_passed = 1 passed_filters.append(high_filter_passed) if params.get('use_CCI_FILTER', False): cci_filter_passed = 0 per = params.get('cci_f_per', 14) if CCI(f.last(symbol, per)) > CCI(f.last(symbol, per, -1)): cci_filter_passed = 1 passed_filters.append(cci_filter_passed) # if params.get('use_COS_FILTER', False): # cos_filter_passed = 0 # per = params.get('cos_f_per', 14) # if CCI(f.last(symbol, per)) > params.get('cos_f_val', 50): # cos_filter_passed = 1 # passed_filters.append(cos_filter_passed) if params.get('use_SMA_FILTER', False): sma_filter_passed = 0 per1 = params.get('sma_f_per_1', 12) # 5 - 15 per2 = params.get('sma_f_per_2', 24) # 16 - 30 per3 = params.get('sma_f_per_3', 50) # 31 - 50 if SMA(f.last(symbol, per1)) > SMA(f.last(symbol, per2)) > SMA( f.last(symbol, per3)): sma_filter_passed = 1 passed_filters.append(sma_filter_passed) all_filters_passed = sum(passed_filters) == len(passed_filters) if all_filters_passed and has_buy_signal: tp_value = cc.close_price * params.get('rel_tp_k', 0.2) if has_buy_signal: allowed_to_buy = True if allowed_to_buy: trade = Trade() trade.open_trade(symbol, 'BUY', cc, cc.close_price, cc.low_price * params.get('init_sl_k', 0.98), cc.close_price + tp_value, open_reason) return trade
def open(cc, c, trades, params): trade = None #ts = trade_stats(trades) allowed_to_buy = False has_buy_signal = False open_reason = None if True: #ts['open'] <= params.get('max_pos', 50): # TAIL if params.get('open_TAIL', False): bs = 0.01 if cc.body_size() == 0 else cc.body_size() if cc.low_tail()/bs > 0.2: has_buy_signal = True open_reason = 'TAIL_BUY' if c.pointer > 5: # BREAKUP if params.get('open_BREAK', False): f = c.last(5, figure=True) if f.is_breakup(): has_buy_signal = True open_reason = 'BREAKUP_BUY' #HAMMER if params.get('open_HAMMER', False): f = c.last(3, figure=True) if f.summary().is_hammer() or f.summary(last=2).is_hammer(): has_buy_signal = True open_reason = 'HAMMER_BUY' #DOUBLE HAMMER if params.get('open_DOUBLE_HAMMER', False): pf = params.get('dh_fast', 2) ps = params.get('dh_slow', 20) if c.last(pf, figure=True).summary().is_hammer() and c.last(ps, figure=True).summary().is_hammer(): has_buy_signal = True open_reason = 'DOUBLE_HAMMER' #FRACTAL if params.get('open_FRACTAL', False): f = c.last(5, figure=True) if f.is_bottom_fractal(): has_buy_signal = True open_reason = 'FRAC_BUY' if params.get('open_C2', False): if CCI(c.last(2)) > CCI(c.last(2, -1)): has_buy_signal = True open_reason = 'C2_BUY' passed_filters = [] if params.get('use_HIGH_FILTER', False): high_filter_passed = 0 max_per = params.get('hf_max_per', 250) th = params.get('hf_max_th', 0.8) if c.pointer > max_per: m = max(bar['high'] for bar in c.last(max_per)) if cc.close_price > m*th: high_filter_passed = 1 passed_filters.append(high_filter_passed) if params.get('use_CCI_FILTER', False): cci_filter_passed = 0 per = params.get('cci_f_per', 14) if CCI(c.last(per)) > CCI(c.last(per, -1)): cci_filter_passed = 1 passed_filters.append(cci_filter_passed) all_filters_passed = sum(passed_filters) == len(passed_filters) if all_filters_passed and has_buy_signal: tp_value = cc.close_price*params.get('rel_tp_k', 0.2) if has_buy_signal: #if ts['open_long'] > ts['open_short'] or ts['open'] == 0: allowed_to_buy = True if allowed_to_buy: trade = Trade() trade.open_trade(c.symbol, 'BUY', cc, cc.close_price, cc.low_price*params.get('init_sl_k', 0.98), cc.close_price + tp_value, open_reason) return trade