Exemple #1
0
class margin_atr_based_risk_management:
    def __init__(self, account_currency, account_id, symbol, timeframe, atr_period, stop_loss_atr_multiply, limit_atr_multiply, risk_percent):
        self.account_currency=account_currency
        self.account_id=account_id
        self.symbol=symbol
        self.timeframe=timeframe
        self.atr_period=int(atr_period)
        self.stop_loss_atr_multiply=stop_loss_atr_multiply
        self.limit_atr_multiply=limit_atr_multiply
        self.risk_percent=risk_percent
        self.db=Db_Controller()


    def get_account_info(self):
        fxcm_info=self.db.query_table('Fxcm_Info', ('*',), fields=("accountId",), values=(self.account_id,))
        return fxcm_info

    def stop_loss_limit(self, price, last_atr, position_type):
        try:
            '''
                stop loss is placed stop_loss_atr_multiply time of atr
            '''

            if position_type=='buy':
                stop_loss_pip=last_atr*self.stop_loss_atr_multiply
                stop_loss=price-stop_loss_pip
                limit_pip=last_atr*self.limit_atr_multiply
                limit=price+limit_pip
            else:
                stop_loss_pip=last_atr*self.stop_loss_atr_multiply
                stop_loss=price+stop_loss_pip
                limit_pip=last_atr*self.limit_atr_multiply
                limit=price-limit_pip
            if self.symbol[3:]=='JPY':
                stop_loss_pip=stop_loss_pip*100
                limit_pip=limit_pip*100
            else:
                stop_loss_pip=stop_loss_pip*10000
                limit_pip=limit_pip*10000


            return stop_loss, limit, stop_loss_pip, limit_pip
        except Exception as e:
            print(e, 'stop_loss_limit')

    def position_size_stop_loss(self, position_type):
        try:
            ''' Lot         Number of unit
                Standard	100,000
                Mini	    10,000
                Micro	    1,000
                Nano	    100
                Position size = ((account value x risk per trade) / pips risked)/ pip value per standard lot
                Margin Requirement = Current Price × Units Traded × Margin
            '''
            data=self.db.query_price_data(self.symbol, self.timeframe, self.atr_period*2)
            data['atr']=atr(list(data.bidclose), self.atr_period)
            last_atr=data.atr.iloc[-1]
            price=data.bidclose.iloc[-1]

            fxcm_info=self.get_account_info()[0]
            margin=fxcm_info[11]
            stop_loss, limit, stop_loss_pip, limit_pip=self.stop_loss_limit(price, last_atr, position_type)
            leverage=leverage_cal(self.symbol, margin)
            standard_lot_pip_value=pip_value_cal(self.symbol, self.account_currency, price, 100000)
            position_size=int(((((margin*self.risk_percent/100)/stop_loss_pip)/standard_lot_pip_value)*100)*1000)
            required_margin=int(price*position_size/leverage)
            c = CurrencyConverter()
            required_margin=int(c.convert(required_margin, self.symbol[:3], self.account_currency))
            if self.symbol[3:]=='JPY':
                required_margin=required_margin/100

            return position_size/1000, required_margin, stop_loss, limit, stop_loss_pip, limit_pip
        except Exception as e:
            print(e, 'position_size_stop_loss')

    def backtest(self, position_type, data, margin):
        try:
            ''' Lot         Number of unit
                Standard	100,000
                Mini	    10,000
                Micro	    1,000
                Nano	    100
                Position size = ((account value x risk per trade) / pips risked)/ pip value per standard lot
                Margin Requirement = Current Price × Units Traded × Margin
            '''
            data['atr']=atr(list(data.bidclose), self.atr_period)
            last_atr=data.atr.iloc[-1]
            price=data.bidclose.iloc[-1]
            
            stop_loss, limit, stop_loss_pip, limit_pip=self.stop_loss_limit(price, last_atr, position_type)
            leverage=leverage_cal(self.symbol, margin)
            standard_lot_pip_value=pip_value_cal(self.symbol, self.account_currency, price, 100000)
            position_size=int(((((margin*self.risk_percent/100)/stop_loss_pip)/standard_lot_pip_value)*100)*1000)
            required_margin=int(price*position_size/leverage)
            c = CurrencyConverter()
            required_margin=int(c.convert(required_margin, self.symbol[:3], self.account_currency))
            pip_value=pip_value_cal(self.symbol, self.account_currency, price, position_size)
            if self.symbol[3:]=='JPY':
                required_margin=required_margin/100

            return position_size, required_margin, stop_loss, limit, stop_loss_pip, limit_pip, pip_value
        except Exception as e:
            print(e, 'backtest')
Exemple #2
0
class Fxcm():
    """
    FXCM controller.
    This class contains methods acting as wrapers for FXCM API class with additional functionality.
    All the methods are direct implementation of FXCM API
    Full documentation can be retrived from: https://fxcm.github.io/rest-api-docs/#section/Overview
    
    """
    def __init__(self):
        with open('./data/account_info.cfg', 'rb'
                  ) as f:  # Reading user's fxcm information from a stored file
            account_info_dict = pickle.load(f)
        self.token = account_info_dict[
            'token']  # FXCM token or API key " a46718dbcf04edf1b8135816d96d38a7703f2d65 " use this in gui
        self.account_type = account_info_dict[
            'account_type']  #Can be demo or real
        self.connection = None
        self.connection_status = 'Disconnected'
        self.db = Db_Controller()
        self.account_id = account_info_dict['account_id']
        self.account_name = account_info_dict['account_name']
        self.fxcm_account_currency_list = ['AUD', 'USD', 'EUR', 'GBP']
        self.account_currency = account_info_dict['account_currency']
        self.available_symbols_list = [
            'AUDUSD', 'EURUSD', 'USDJPY', 'GBPUSD', 'USDCHF', 'NZDUSD'
        ]
        self.available_timeframe_list = [
            'm1', 'm5', 'm15', 'm30', 'H1', 'H2', 'H3', 'H4', 'H6', 'H8', 'D1',
            'W1', 'M1'
        ]

    def timestamp_to_datetime(self, given_time):
        """
        This function converts timestamp to datetime
        """
        given_time = str(given_time)
        if len(given_time) == 13:
            given_time = str(0) + given_time
            new_time = datetime.datetime.strptime(given_time, '%m%d%Y%H%M%S')
            new_time = new_time.strftime("%Y-%m-%d %H:%M")
            return new_time
        elif len(given_time) == 14:
            new_time = datetime.datetime.strptime(given_time, '%m%d%Y%H%M%S')
            new_time = new_time.strftime("%Y-%m-%d %H:%M")
            return new_time
        elif len(given_time) == 16:
            given_time = str(0) + given_time
            new_time = datetime.datetime.strptime(given_time, '%m%d%Y%H%M%S%f')
            new_time = new_time.strftime("%Y-%m-%d %H:%M")
            return new_time
        elif len(given_time) == 17:
            new_time = datetime.datetime.strptime(given_time, '%m%d%Y%H%M%S%f')
            new_time = new_time.strftime("%Y-%m-%d %H:%M")
            return new_time

    def connect(self, startegy_name):
        """
        This function makes an instance of fxcmpy.fxcmpy to connect to server, and is used by auto trading system for creating connection
        Once the fxcmpy instance is created, two new threads will be created as fxcmpy does that automatically.
        the name of its thread can be gotten from 'socket_thread._name' on the connection object. when closing the connection
        this name is used to stop its thread
        """
        if self.connection == None or self.connection.is_connected() != True:
            try:
                self.disconnect()
                self.connection = fxcmpy(access_token=self.token,
                                         log_level='error',
                                         server=self.account_type)
                if self.connection.is_connected():
                    self.connection_status = 'Connected'
                else:
                    self.disconnect()
                    self.connection_status = 'Disconnected'
            except:
                self.connection_status = 'Disconnected'
                self.disconnect()

    def connect_gui(self):
        """
        This function makes an instance of fxcmpy.fxcmpy to connect to server, and is used by gui for creating connection and starting required threads
        Once the fxcmpy instance is created, two new threads will be created as fxcmpy does that automatically.
        the name of its thread can be gotten from 'socket_thread._name' on the connection object. when closing the connection
        this name is used to stop its thread
        """

        try:
            if self.connection == None or self.connection.is_connected(
            ) != True:
                self.disconnect_gui()
                self.connection = fxcmpy(access_token=self.token,
                                         log_level='error',
                                         server=self.account_type)
                connection_status = self.connection.is_connected()
                if connection_status != True:
                    self.connection_status = 'Disconnected'
                    self.disconnect_gui()
                    return 'Problem in connection'
                else:
                    self.connection_status = 'Connected'
                    account_info = self.connection.get_accounts(
                    )  #Getting account info data
                    # Inserting account info data if not exits into db
                    if len(
                            self.db.query_table(
                                'Fxcm_Info', ('accountId', ),
                                fields=('accountId', ),
                                values=(self.account_id, ))) == 0:
                        self.db.insert_into_account_info_table(account_info)
                    return True
            else:
                'Connection is already established'
        except Exception as e:
            self.disconnect_gui()
            return str(e)

    def start_connection_thread_gui(self):
        """
        This function is called from login page when connect button is clicked.
        It calls connect_gui ethod to establish connection and then calls gui_threads
        to create and start threads for updating fxcm data
        """
        result = self.connect_gui()
        if result == True:
            self.gui_threads()
            return True
        else:
            return result

    def gui_threads(self):
        """
        This method initializes threads for updating fxcm data 
        """
        class update_all_info_thread(threading.Thread):
            """
            This class inherits from threading.Thread class. Created to handle updating account data, open positions, closed positions
            and price data for chart
            """
            def __init__(self, fxcm_instance, symbol, timeframe):
                threading.Thread.__init__(self)
                self.event = threading.Event()
                self.fxcm_instance = fxcm_instance
                self.symbol = symbol
                self.timeframe = timeframe
                self.name = 'Update_info_thread'
                self.change_symbol_timeframe_signal = False
                self.change_symbol_timeframe(self.symbol, self.timeframe)

            def change_symbol_timeframe(self, symbol, timeframe):
                """
                This method changes symbol and timeframe for getting price data
                """
                self.fxcm_instance.db.create_price_data_table(
                    symbol, timeframe
                )  #Creating price data table for new symbol and timeframe
                self.symbol = symbol
                self.timeframe = timeframe
                self.change_symbol_timeframe_signal = True

            def stop(self):
                self.event.set()

            def run(self):
                while True:
                    try:
                        if self.event.is_set() == True:
                            break
                        else:
                            connection_status = self.fxcm_instance.connection.is_connected(
                            )
                            if connection_status == True:
                                self.fxcm_instance.connection_status = 'Connected'
                                self.fxcm_instance.get_acc_info()
                                time.sleep(1)
                                self.fxcm_instance.get_open_positions()
                                time.sleep(1)
                                self.fxcm_instance.get_closed_positions()
                                time.sleep(1)
                                if self.change_symbol_timeframe_signal == True:
                                    candle_result = self.fxcm_instance.get_price_data(
                                        self.symbol, self.timeframe)
                                    if candle_result == True:
                                        self.change_symbol_timeframe_signal = False
                                    else:
                                        self.fxcm_instance.disconnect_gui()
                                        time.sleep(30)
                                        self.fxcm_instance.connect_gui()
                                else:
                                    candle_result = self.fxcm_instance.get_price_data(
                                        self.symbol, self.timeframe, 100)
                                    if candle_result == False:
                                        self.fxcm_instance.disconnect_gui()
                                        time.sleep(30)
                                        self.fxcm_instance.connect_gui()
                            else:
                                self.fxcm_instance.connection_status = 'Disconnected'
                                self.fxcm_instance.disconnect_gui()
                                time.sleep(30)
                                self.fxcm_instance.connect_gui()
                                self.event.clear()

                            time.sleep(10)
                    except:
                        self.fxcm_instance.connection_status = 'Disconnected'
                        self.fxcm_instance.disconnect_gui()
                        time.sleep(30)
                        self.fxcm_instance.connect_gui()
                        self.event.clear()

        #Creating an instance of update_all_info_thread and starting it to start updating required data
        self.all_info_thread = update_all_info_thread(
            self, self.available_symbols_list[0],
            self.available_timeframe_list[0])
        self.all_info_thread.start()

    def disconnect(self):
        """
        This method disconnect autotrading fxcm connection objects 
        """
        try:
            self.connection.socket._heartbeat_thread._halt.set()
            self.connection = None
            self.connection_status = 'Disconnected'
        except:
            self.connection = None
            self.connection_status = 'Disconnected'

    def disconnect_gui(self):
        """
        This method disconnect gui fxcm connection objects and stop update related threads
        """
        try:
            try:
                self.all_info_thread.stop(
                )  #Stoping the thread of updating information
            except:
                pass

            try:
                self.connection.socket._heartbeat_thread._halt.set()
                self.connection = None
                self.connection_status = 'Disconnected'
            except:
                self.connection = None
                self.connection_status = 'Disconnected'
        except:
            pass

    def change_symbol_timeframe_chart(self, symbol, timeframe):
        """
        This method is called from gui to change symbol and timeframe used in update_all_info_thread to get new data
        """
        try:
            self.all_info_thread.change_symbol_timeframe(symbol, timeframe)
        except:
            pass

    def get_price_data(self, trading_symbol, timeframe, quantity=10000):
        """
        This method gets price data for given symbol and timeframe from fxcm and sends it to be stored in db
        """
        try:
            symbol = list(trading_symbol)
            symbol.insert(3, '/')
            symbol = ''.join(symbol)
            data = pd.DataFrame()
            data = self.connection.get_candles(symbol,
                                               period=timeframe,
                                               number=quantity)
            if data.empty != True:
                self.db.insert_into_price_data_table(data, trading_symbol,
                                                     timeframe)
                return True
            else:
                return False
        except:
            return False

    def get_acc_info(self):
        """
        This method gets account info from fxcm and sends it to be stored in db
        """
        acc_info = self.connection.get_accounts()
        self.db.update_account_info_table(self.account_id, acc_info)

    def update_token(self, new_token, account_currency, account_type):
        """
        This method updates token and account currency.
        It does not only changes the token value, it validates it by connecting to server using given token and account type
        and if the connection is established, the it get account info from fxcm to store accountId and accountName and
        finally it disconnects and store update token, accountId and accountName, account type and account currency in a
        file named account_info.cfg.
        """
        try:
            self.token = new_token
            self.account_type = account_type
            self.account_currency = account_currency
            self.connection = fxcmpy(access_token=self.token,
                                     log_level='error',
                                     server=self.account_type)
            account_info = self.connection.get_accounts()
            self.disconnect()

            self.account_id = account_info.accountId.iloc[0]
            self.account_name = account_info.accountName.iloc[0]
            if len(
                    self.db.query_table('Fxcm_Info', ('accountId', ),
                                        fields=('accountId', ),
                                        values=(self.account_id, ))) == 0:
                self.db.insert_into_account_info_table(account_info)
            with open('./data/account_info.cfg', 'rb') as f:
                account_info_dict = pickle.load(f)
            account_info_dict['token'] = self.token
            account_info_dict['account_type'] = self.account_type
            account_info_dict['account_id'] = self.account_id
            account_info_dict['account_name'] = self.account_name
            account_info_dict['account_currency'] = self.account_currency
            with open('./data/account_info.cfg', 'wb') as f:
                pickle.dump(account_info_dict, f)
            self.connection = None
            return True
        except Exception as e:
            try:
                self.disconnect()
            except:
                pass
            self.connection = None
            self.account_id = None
            self.account_name = None
            self.account_type = ''
            self.token = ''
            self.account_currency = None
            return str(e)

    def get_open_positions(self):
        """
        This method gets open positions from fxcm and sends it to be stored in db
        """
        open_positions = self.connection.get_open_positions()
        self.db.update_open_positions_table(open_positions, self.account_id)

    def get_open_trade_ids(self):
        return self.connection.get_open_trade_ids()

    def get_closed_positions(self):
        """
        This method gets closed positions from fxcm and sends it to be stored in db
        """
        closed_positions = self.connection.get_closed_positions()
        self.db.update_closed_positions_table(closed_positions)

    def open_position(self, **position_parameters):
        try:
            print('open_position...............')
            """
            Function to add a position to FXCM server
            
            Inputs: **position_parameters->dictionary List of different variables to open a position
            Output: Opened position and created db row and tradeId
            """
            position_maker = position_parameters['maker']
            symbol = position_parameters['symbol']
            symbol = list(symbol)
            symbol.insert(3, '/')
            symbol = ''.join(symbol)
            del position_parameters['maker']
            position_parameters['symbol'] = symbol
            order = self.connection.open_trade(**position_parameters)
            trade_id = int(order.get_tradeId())

            while True:
                open_positions = self.connection.get_open_positions()
                data = open_positions.loc[open_positions['tradeId'] == str(
                    trade_id)]
                if data.empty == False:
                    break
                time.sleep(10)
            data['positionMaker'] = [
                position_maker,
            ]
            self.db.insert_into_open_positions(data)
            return trade_id
        except:
            return None

    def close_position(self, **position_parameters):
        try:
            print('close_position...............')
            """
            Function to close a position from FXCM server
            
            Inputs: **position_parameters->dictionary List of different variables to close a position
            Output: Closed FXCM position, deleted OpenPosition row and created ClosedPosition row in db
            """
            position_maker = position_parameters['maker']
            del position_parameters['maker']
            self.connection.close_trade(**position_parameters)
            self.db.delete_from_table('OpenPosition',
                                      position_parameters['trade_id'])
            closed_positions = self.connection.get_closed_positions()
            closed_position = closed_positions.loc[
                closed_positions['tradeId'] == str(
                    position_parameters['trade_id'])]
            closed_position['positionMaker'] = [
                position_maker,
            ]
            self.db.insert_into_closed_positions(closed_position)
            return True
        except Exception as e:
            print(e)
            return False

    def edit_position_stop_limit(self, **position_parameters):
        """
        This method edits an open position
        """
        try:
            self.connection.change_trade_stop_limit(**position_parameters)
        except:
            pass

    def close_all_positions(self):
        """
        This method closess all open positions 
        """

        try:
            data = self.connection.get_open_positions()
            for i, j in enumerate(data.tradeId):
                self.db.delete_from_table('OpenPosition', j)
            self.connection.close_all()
            data = self.connection.get_closed_positions()
            makers_list = []
            for i in range(len(data.tadeId)):
                makers_list.append('Manual')
            data['positionMaker'] = makers_list
            self.db.insert_into_closed_positions(data)
        except:
            pass

    def get_open_positions_ids(self):
        try:
            return self.connection.get_open_trade_ids()
        except:
            return []

    def get_default_acc_id(self):
        try:
            return self.connection.get_default_account()
        except:
            return []