XTBApi icon indicating copy to clipboard operation
XTBApi copied to clipboard

I have picked it up and added the functions buy_limit and sell_limit

Open Leci37 opened this issue 1 year ago • 0 comments

Hello, first of all congratulate you for your work.

I have picked it up and added the functions buy_limit and sell_limit ( more info https://www.xtb.com/int/education/xstation-5-pending-orders ) I am using your API, to finish defining my project https://github.com/Leci37/stocks-Machine-learning-RealTime-telegram

Example of how to call the function, when the porcetage order_margin_per is set to non-zero, that is the procentage at which the buy-sell order should be executed. if it is zero the order is executed as standard buy-sell. take profit and stop loss (tp_per=0.07, sl_per=0.02) are expressed in the percentage at which the stock has to go down or up to be executed automatically. it is also possible to buy by number of dollars and not by volume through dolars=100, and add a custom message to each function with custom_Messege="Messege" (although it doesn't work for me)

#OPEN BUY
client.open_trade('buy', 'ETHEREUM', dolars=100, custom_Messege="buy", tp_per=0.07, sl_per=0.02)
#OPEN SELL
client.open_trade('sell', 'ETHEREUM', dolars=100, custom_Messege="sell", tp_per=0.07, sl_per=0.02)
#ORDER BUY when price reduce 0.01percentage order_margin_per=-0.01
client.open_trade('buy', 'ETHEREUM', dolars=100, custom_Messege="ORDER BUY", tp_per=0.07, sl_per=0.02, order_margin_per=-0.004, expiration_stamp=expitarion_timestamp)
#ORDER SELL when price increase  0.01percentage order_margin_per=0.01
client.open_trade('sell', 'ETHEREUM', dolars=100, custom_Messege="ORDER SELL", tp_per=0.07, sl_per=0.02, order_margin_per=+0.004, expiration_stamp=expitarion_timestamp)

Result view image

for the expiration time expiration_stamp=expitarion_timestamp, if the transaction has not entered it is needed

import datetime
def get_expiration_timeStamp(minutes):
    expitarion_timestamp = datetime.datetime.now().replace(microsecond=0) + datetime.timedelta(minutes=minutes)
    expitarion_timestamp = int(datetime.datetime.timestamp(expitarion_timestamp)) * 1000
    return expitarion_timestamp

I attach the necessary changes in the method, perhaps it can be added with another name to the API, and the entire final file, I have also added the alternative managements to 3 types of errors that can give the answer (the added auxiliary methods are in the attached file). api_FULL_code_python.txt

   def open_trade(self, mode, symbol, dolars =0, custom_Messege ="", tp_per = 0.05, sl_per= 0.05, order_margin_per = 0, expiration_stamp = 0):
        """open trade transaction"""
        if mode in [MODES.BUY.value, MODES.SELL.value]:
            mode = [x for x in MODES if x.value == mode][0]
        elif mode in ['buy', 'sell']:
            modes = {'buy': MODES.BUY, 'sell': MODES.SELL}
            mode = modes[mode]
        else:
            raise ValueError("mode can be buy or sell")

        price, price_2 = self.get_prices_operate(mode, symbol)

        if order_margin_per != 0:
            # https://www.xtb.com/int/education/xstation-5-pending-orders
            mode, mode_name = self.change_to_order_type_mode(mode.name)
        else:
            mode_name = mode.name
            mode = mode.value

        self.LOGGER.debug(f"opening trade of {symbol} of Dolars: {dolars} with {mode_name}  Expiration: {datetime.fromtimestamp(expiration_stamp/1000) }")
        price = round(price * (1 + order_margin_per) , 2) #No mas de 3 decimales

        if dolars != 0:
            round_value = 0
            if len(str(int(price))) >= 4:#para valores muy grandes como el bitcoin
                round_value = 2
            volumen = round((dolars / price) , round_value)
            if 1 > volumen and ".US" in symbol:
                self.LOGGER.warning(f"Volume cannot be less than 1 in Stocks ,symbol:  {symbol} ")
                volumen = 1

        if dolars <= 0:
            raise ValueError(f"The value in dollars is lower than expected :{dolars}")
        sl, tp = self.get_tp_sl(mode, price, sl_per, tp_per)

        # trans_type = TRANS_TYPES.PENDING.value

        response = self.trade_transaction(symbol, mode, trans_type = 0,volume = volumen, price=price,
                                          customComment=custom_Messege,tp=tp, sl=sl, expiration = expiration_stamp  )
        # response = self.trade_transaction(symbol, MODES.SELL_LIMIT.value, 0, volume=volumen_with_dolars, price=price,customComment=custom_Messege, tp=tp, sl=sl)
        status, status_messg = self.manage_response(expiration_stamp, response)
        if status_messg == 'Invalid prices(limit)':
            response = self.trade_transaction(symbol, mode, trans_type=0, volume=volumen, price=price_2,customComment=custom_Messege, tp=tp, sl=sl, expiration=expiration_stamp)
            status, status_messg = self.manage_response(expiration_stamp, response)
            price = price_2
        if status_messg == 'Invalid s/l or t/p price':
            sl, tp = self.get_tp_sl(mode, price, sl_per+ 0.012, tp_per+ 0.012)
            response = self.trade_transaction(symbol, mode, trans_type=0, volume=volumen, price=price,customComment=custom_Messege, tp=tp, sl=sl, expiration=expiration_stamp)
            status, status_messg = self.manage_response(expiration_stamp, response)
        if status_messg == 'SL/TP order not supported' or status_messg == 'Short selling not available':
            print('FAIL. opening trade of '+symbol+' Message: '+status_messg+' Stock: '+ symbol + " ")
            return response


        #'Instrument is quoted in close only mode' FAIL 100%      'Instrument is quoted in close only mode'
        if status != 3:
            self.LOGGER.debug(f"FAIL. opening trade of {symbol} Message: {status_messg} of Dolars: {dolars} with {mode_name} Expiration: {datetime.fromtimestamp(expiration_stamp / 1000)}")
            raise TransactionRejected(status + " Message : "+ status_messg + ' Stock '+symbol+ " Volumne: "+str(volumen))
        else:
            self.LOGGER.debug(f"Successfully. opening trade of {symbol} of Dolars: {dolars} with {mode_name} Expiration: {datetime.fromtimestamp(expiration_stamp/1000)}")
        return response

Leci37 avatar Dec 08 '22 13:12 Leci37