Files
qsforex/portfolio/position.py

112 lines
4.3 KiB
Python

from decimal import Decimal, getcontext, ROUND_HALF_DOWN
class Position(object):
def __init__(
self, home_currency, position_type,
currency_pair, units, ticker
):
self.home_currency = home_currency # Account denomination (e.g. GBP)
self.position_type = position_type # Long or short
self.currency_pair = currency_pair # Intended traded currency pair
self.units = units
self.ticker = ticker
self.set_up_currencies()
self.profit_base = self.calculate_profit_base()
self.profit_perc = self.calculate_profit_perc()
def set_up_currencies(self):
self.base_currency = self.currency_pair[:3] # For EUR/USD, this is EUR
self.quote_currency = self.currency_pair[3:] # For EUR/USD, this is USD
# For EUR/USD, with account denominated in GBP, this is USD/GBP
self.quote_home_currency_pair = "%s%s" % (self.quote_currency, self.home_currency)
ticker_cur = self.ticker.prices[self.currency_pair]
if self.position_type == "long":
self.avg_price = Decimal(str(ticker_cur["ask"]))
self.cur_price = Decimal(str(ticker_cur["bid"]))
else:
self.avg_price = Decimal(str(ticker_cur["bid"]))
self.cur_price = Decimal(str(ticker_cur["ask"]))
def calculate_pips(self):
mult = Decimal("1")
if self.position_type == "long":
mult = Decimal("1")
elif self.position_type == "short":
mult = Decimal("-1")
pips = (mult * (self.cur_price - self.avg_price)).quantize(
Decimal("0.00001"), ROUND_HALF_DOWN
)
return pips
def calculate_profit_base(self):
pips = self.calculate_pips()
ticker_qh = self.ticker.prices[self.quote_home_currency_pair]
if self.position_type == "long":
qh_close = ticker_qh["bid"]
else:
qh_close = ticker_qh["ask"]
profit = pips * qh_close * self.units
return profit.quantize(
Decimal("0.00001"), ROUND_HALF_DOWN
)
def calculate_profit_perc(self):
return (self.profit_base / self.units * Decimal("100.00")).quantize(
Decimal("0.00001"), ROUND_HALF_DOWN
)
def update_position_price(self):
ticker_cur = self.ticker.prices[self.currency_pair]
if self.position_type == "long":
self.cur_price = Decimal(str(ticker_cur["bid"]))
else:
self.cur_price = Decimal(str(ticker_cur["ask"]))
self.profit_base = self.calculate_profit_base()
self.profit_perc = self.calculate_profit_perc()
def add_units(self, units):
cp = self.ticker.prices[self.currency_pair]
if self.position_type == "long":
add_price = cp["ask"]
else:
add_price = cp["bid"]
new_total_units = self.units + units
new_total_cost = self.avg_price*self.units + add_price*units
self.avg_price = new_total_cost/new_total_units
self.units = new_total_units
self.update_position_price()
def remove_units(self, units):
dec_units = Decimal(str(units))
ticker_cp = self.ticker.prices[self.currency_pair]
ticker_qh = self.ticker.prices[self.quote_home_currency_pair]
if self.position_type == "long":
remove_price = ticker_cp["ask"]
qh_close = ticker_qh["bid"]
else:
remove_price = ticker_cp["bid"]
qh_close = ticker_qh["ask"]
self.units -= dec_units
self.update_position_price()
# Calculate PnL
pnl = self.calculate_pips() * qh_close * dec_units
getcontext().rounding = ROUND_HALF_DOWN
return pnl.quantize(Decimal("0.01"))
def close_position(self):
ticker_cp = self.ticker.prices[self.currency_pair]
ticker_qh = self.ticker.prices[self.quote_home_currency_pair]
if self.position_type == "long":
remove_price = ticker_cp["ask"]
qh_close = ticker_qh["bid"]
else:
remove_price = ticker_cp["bid"]
qh_close = ticker_qh["ask"]
self.update_position_price()
# Calculate PnL
pnl = self.calculate_pips() * qh_close * self.units
getcontext().rounding = ROUND_HALF_DOWN
return pnl.quantize(Decimal("0.01"))