import unittest
import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from optrabot.stoplossadjuster import StopLossAdjuster

class StopLossAdjusterTests(unittest.TestCase):
	
	def test_RegularStopAdjustmentNoOffset(self):
		"""
		Tests if the stop is adjusted to 10% based on the trigger profit level of 10%
		"""
		entryPrice = 100.00
		adjuster = StopLossAdjuster(reverse=False, trigger=10, stop=10)
		adjuster.setBasePrice(entryPrice)
		adjustedStop = adjuster.execute(100)
		self.assertEquals(adjustedStop, None)
		# $10 Profit entspricht 10% -> Sollte angepassten Stop zurück liefern
		adjustedStop = adjuster.execute(entryPrice+10)
		# Neuer Stop muss bei 99 liegen
		self.assertEquals(adjustedStop, 99)
		self.assertEquals(adjuster.isTriggered(), True)
	
	def test_RegularStopAdjustmentWithOffset(self):
		entryPrice = 5.0
		adjuster = StopLossAdjuster(reverse=False, trigger=10, stop=5, offset=0.2)
		adjuster.setBasePrice(entryPrice)
		adjustedStop = adjuster.execute(4.99)
		self.assertEquals(adjustedStop, None)
		adjustedStop = adjuster.execute(-1)
		self.assertEquals(adjustedStop, None)
		self.assertEquals(adjuster.isTriggered(), False)
		# 5,5 Profit entspricht 10% -> Stop Preis muss angepasst werden
		adjustedStop = adjuster.execute(5.5)
		# Neuer Stop Preis is 5% unter dem Trigger Preis und noch 0.2 näher am Markt
		self.assertEquals(adjustedStop, 5.425)
		self.assertEquals(adjuster.isTriggered(), True)
		# Bei höherem Profit darf der Stop Adjuster keinen angepassten Preis mehr liefern
		adjustedStop = adjuster.execute(6)
		self.assertEquals(adjustedStop, None)
		# Bei niedrigerem Profit darf der Stop Adjuster keinen angepassten Preis mehr liefern
		adjustedStop = adjuster.execute(3)
		self.assertEquals(adjustedStop, None)
	
	def test_ReverseStopAdjustmentNoOffset(self):
		entryPrice = 15.0
		adjuster = StopLossAdjuster(reverse=True, trigger=5, stop=10)
		adjuster.setBasePrice(entryPrice)
		# Bei höherem Preis darf keine Stop Anpassung passieren
		adjustedStop = adjuster.execute(15.01)
		self.assertEquals(adjustedStop, None)
		# Bei niedrigerem Preis, aber unterhalb des Profit Levels ebenfalls keine Anpassung
		adjustedStop = adjuster.execute(14.26)
		self.assertEquals(adjustedStop, None)
		self.assertEquals(adjuster.isTriggered(), False)
		# Wenn Trigger Preis erreicht, dann Stop Anpassung auf 10% vom Trigger Preis, d.h. 15.675
		adjustedStop = adjuster.execute(14.25)
		self.assertEquals(adjustedStop, 15.675)
		self.assertEquals(adjuster.isTriggered(), True)
		# Bei höherem Profit darf der Stop Adjuster keinen angepassten Preis mehr liefern
		adjustedStop = adjuster.execute(12)
		self.assertEquals(adjustedStop, None)
		# Bei niedrigerem Profit darf der Stop Adjuster keinen angepassten Preis mehr liefern
		adjustedStop = adjuster.execute(16)
		self.assertEquals(adjustedStop, None)
	
	def test_ReverseStopAdjustmentWithPositiveOffset(self):
		"""
		Testet den Reverse Stop Adjuster mit einem positiven Offset, der den Stop näher an den Markt heranführt,
		d.h. den Preis noch verringert.
		"""
		entryPrice = 30.0
		adjuster = StopLossAdjuster(reverse=True, trigger=5, stop=10, offset=0.20)
		adjuster.setBasePrice(entryPrice)
		# Bei höherem Preis darf keine Stop Anpassung passieren
		adjustedStop = adjuster.execute(30.30)
		self.assertEquals(adjustedStop, None)
		# Bei niedrigerem Preis, aber unterhalb des Profit Levels ebenfalls keine Anpassung
		adjustedStop = adjuster.execute(28.51)
		self.assertEquals(adjustedStop, None)
		self.assertEquals(adjuster.isTriggered(), False)
		# Wenn Trigger Preis erreicht, dann Stop Anpassung auf 10% + offset, d.h. 31,35 - 0,20 = 31,15
		adjustedStop = round(adjuster.execute(28.40),2)
		self.assertEquals(adjustedStop, 31.15)
		self.assertEquals(adjuster.isTriggered(), True)

	def test_ReverseStopAdjustmentWithNegativeOffset(self):
		"""
		Testet den Reverse Stop Adjuster mit einem negativen Offset, der den Stop weiter weg vom Markt legt,
		d.h. den Preis noch verringert.
		"""
		entryPrice = 30.0
		adjuster = StopLossAdjuster(reverse=True, trigger=5, stop=10, offset=-0.20)
		adjuster.setBasePrice(entryPrice)
		# Bei höherem Preis darf keine Stop Anpassung passieren
		adjustedStop = adjuster.execute(30.30)
		self.assertEquals(adjustedStop, None)
		# Wenn Trigger Preis erreicht, dann Stop Anpassung auf 10% + offset, d.h. 31,35 + 0,20 = 31,55
		adjustedStop = adjuster.execute(28.40)
		self.assertEquals(adjustedStop, 31.55)
		self.assertEquals(adjuster.isTriggered(), True)
	
	def test_ReverseStopAdjustmentBreakEvenNegativeOffset(self):
		""" Es soll beim erreichen von 10% Profit der Stop auf Breakeven gesetzt werden und $0,20 näher an
		den Markt heran, um beim Stop Loss die Gebühren des Trades wenigstens verdient zu haben.
		"""
		entryPrice = 30.0
		adjuster = StopLossAdjuster(reverse=True, trigger=5, stop=5, offset=0.20)
		adjuster.setBasePrice(entryPrice)
		adjustedStop = adjuster.execute(28.0)
		self.assertEquals(adjustedStop, 29.725)
		self.assertEquals(adjuster.isTriggered(), True)
		adjuster.resetTrigger()
		self.assertEquals(adjuster.isTriggered(), False)
	
	# def test_ReverseStopAdjustmentNegativeStop(self):
	# 	""" Beim Erreichen von 15% Profit soll der Stop auf Breakeven +8% herangezogen werden, so dass
	# 	man beim Stop dann 8% Profit gemacht hat. 
	# 	"""
	# 	entryPrice = 30.0
	# 	adjuster = StopLossAdjuster(reverse=True, trigger=15, stop=-8, offset=0)
	# 	adjuster.setBasePrice(entryPrice)
	# 	adjustedStop = adjuster.execute(25.0)
	# 	self.assertEquals(adjustedStop, 27.60)
	# 	self.assertEquals(adjuster.isTriggered(), True)