Welcome to NJ4X Copy Trading API’s documentation!

Assume ForexGiants.com is a company which attracts clients to its business and keeps some customer records - names, emails, bank details etc. Suppose we have two records in Customers table of that system:

Customers @ ForexGiants.com
Client ID Name Email
10013 John Brook john.b@gmail.com
20015 Alice Cooper alice.c@yahoo.com

In this scenario 10013 is a Client ID of John Brook and 20015 is a Client ID of Alice Cooper.

Let’s assume that John Brook is a professional and successful Forex trader. He’d like to register his existing MT4 account (#123456 @ Alpari.com) within the Copy Trading system. It will make possible for him to gain more money as his account is promoted to other customers and they follow his trading activity.

In the Copy Trading system there will be two records then:

mt_account Id: 772, ClientId: 10013, Broker: ‘Alpari’, AccountNumber: 123456, …
leader Id: 772, ClientId: 10013, MtAccountRef: 772, TradedSymbols: [‘AUDCAD’, ‘AUDJPY’, ‘EURUSD’, …], …

Alice Cooper is new to Forex trading. She has found John Brook as a good trader and wants to follow him. She registers MT4 account #5554321 at Forex.com …

In the Copy Trading system another two records shall arrive:

mt_account Id: 987, ClientId: 20015, Broker: ‘Forex.com’, AccountNumber: 5554321, …
follower Id: 1277, ClientId: 20015, TradeCopierAccountRef: 987, LeaderRef: 772, ‘CopyRules’: [{‘LeaderSymbol’: ‘EURUSD’,’FollowerSymbol’: ‘EURUSD’,’SymbolCopyRuleMode’: {‘Mode’: 0 #OneToOne}, …]

Now the Copy Trading system will monitor trades on a John’s account and generate copy of those trades at Alice’s MT4 account.

Alice shall pay some fee to John for a usage of his expertise - but it is out of scope of the Copy Trading system…

Indices and tables

Give me some code

Connect to WAMP router (Python, see more detailed examples here)

from autobahn.twisted.component import Component
from autobahn.twisted.component import run

wamp_comp = Component(
    transports=u"ws://185.82.217.120:8070",
    realm="nj4x
)

@wamp_comp.on_join
def joined(session, details):
    print("Connected to router: {}".format(session))

if __name__ == "__main__":
    run([wamp_comp])

Copy trading API demo

@wamp_comp.on_join
@inlineCallbacks
def nj4x_copy_trading_api_demo(session, details):
    # local config
    is_recreate_accounts = True
    client_id = 4
    #
    if is_recreate_accounts:
        yield from ct_demo_cleanup(client_id)
        mt4_leader_acct = yield from ct_demo_create_mt_acct(client_id, broker="demo1-amsterdam.fxpro.com",
                                                            acct_number=6796186, passwd="dpkk4hg")
        leader = yield from ct_demo_register_leader_acct(client_id, mt4_leader_acct)
        mt4_follower_acct = yield from ct_demo_create_mt_acct(client_id, "HantecMarkets-Demo", 253645867, "5azgsvd")
        # ---------------------------------
        # Create Follower configuration
        # ---------------------------------
        follower = yield from ct_followers_service.create(
            {'ClientId': client_id,
             'TradeCopierAccountRef': mt4_follower_acct["Id"],
             'LeaderRef': leader["Id"],
             'IsVerified': True,
             # 'CutLossPercentage': 5.0,
             # 'CutLossAmount': 0.0,
             # 'CutLossEquity': 0.0,
             # 'MinMarginLevel': 0,
             # 'MinLotFractionToTrade': 0.5,
             # 'ReducedPeriodAction': 1,
             # 'RemovedRuleAction': 1,
             # 'IsKeepCopiedOrdersWhenDeleted': False,
             # 'IsRenewManuallyClosedCopies': False,
             'CopyRules': [
                 {
                     'LeaderSymbol': 'EURUSD',
                     'FollowerSymbol': 'EURUSD',
                     'SymbolCopyRuleMode': {
                         'Mode': 0  # OneToOne
                     },
                     'MinLot': 0.01,
                     'MaxLot': 100000.0
                 },
                 {
                     'LeaderSymbol': 'AUDUSD',
                     'FollowerSymbol': 'AUDUSD',
                     'SymbolCopyRuleMode': {
                         'Mode': 1,  # WithPercentageMultiplier
                         'PercentageMultiplier': 50.0
                     },
                     'IsAdjustByLeverageRatio': True,
                     'MinLot': 0.01,
                     'MaxLot': 100000.0
                 },
                 {
                     'LeaderSymbol': 'USDJPY',
                     'FollowerSymbol': 'USDJPY',
                     'SymbolCopyRuleMode': {
                         'Mode': 5,  # FixedNoOfLots
                         'FixedLots': 0.01
                     },
                     'MinLot': 0.01,
                     'MaxLot': 100000.0
                 }
             ]
             })
        print("Created follower: {}".format(follower))
        yield sleep(10)
    else:
        mt4_leader_acct = yield from ct_demo_find_mt_acct(client_id, 6796186)
        leader = (yield ct_leaders_service.find_by_client_id(client_id))[0]
        mt4_follower_acct = yield from ct_demo_find_mt_acct(client_id, 253645867)
        follower = (yield ct_followers_service.find_by_trade_copier_account_id(mt4_follower_acct["Id"]))[0]
    print("-" * 32)
    # -------------------------------------------------
    # Get active copied trades
    # -------------------------------------------------
    active_trades = yield ct_followers_service.get_paged_active_trades(follower, paging_req=None)
    for t in active_trades["PageRows"]:
        print("Active copy trade: {}".format(t))
    print("-" * 32)
    # -------------------------------------------------
    # Get active copy order mappings
    # -------------------------------------------------
    follower = yield ct_followers_service.find_by_id(follower["Id"])
    for o in follower["CurrentOrders"]:
        print("Active copy order: master ticket {} -> follower ticket {}, copy started at {} is_error?={} reject_reason={}".format(o["MOrderRef"], o["FOrderRef"], o["StartTimeUtc"], o["IsError"], o.get("RejectReason")))
        print("\tLeader's order  : {}".format(o["MOrderInfo"]))
        print("\tFollower's order: {}".format(o["FOrderInfo"]))
    print("-" * 32)
    yield sleep(10)
    # -------------------------------------------------
    # Update MT4 account (Broker/AccountNumber/Password)
    # -------------------------------------------------
    mt4_leader_acct['Password'] = 'dpkk4hg'  # password update
    updated_acct = yield mt_accounts_service.update(mt4_leader_acct)
    print("Updated Account: {}".format(updated_acct))
    # -------------------------------------------------
    # Get account's info
    # -------------------------------------------------
    info = yield mt_accounts_service.get_info(mt4_leader_acct)
    print("Info: {}".format(info))
    print("-" * 32)
    # -------------------------------------------------
    # Get account's live orders (work with pages)
    # -------------------------------------------------
    page = yield mt_accounts_service.get_paged_active_trades(mt4_leader_acct, {'PageSize': 2, 'PageNo': 0})
    for o in page['PageRows']:
        print("Active trade: {}".format(o))
    for p in range(1, page['TotalPages']):
        next_page = yield mt_accounts_service.get_paged_active_trades(mt4_leader_acct, {'PageNo': p, 'PageSize': 2})
        for o in next_page['PageRows']:
            print("Active trade: {}".format(o))
    print("-" * 32)
    # -------------------------------------------------
    yield from ct_demo_global_lookups()
    # -------------------------------------------------
    # Release WAMP connection (optional)
    # -------------------------------------------------
    session.leave()
def ct_demo_cleanup(client_id):
    # -------------------------------------------------
    # Clean-up Demo Followers (lookup by ClientId)
    # -------------------------------------------------
    ct_followers = yield ct_followers_service.find_by_client_id(client_id)
    for f in ct_followers:
        try:
            yield ct_followers_service.delete(f)
            print("Removed Follower: {}".format(f))
        except Exception as e:
            print("Follower delete error: {}".format(e))
    # -------------------------------------------------
    # Clean-up Demo Leaders (lookup by ClientId)
    # -------------------------------------------------
    ct_leaders = yield ct_leaders_service.find_by_client_id(client_id)
    for l in ct_leaders:
        try:
            yield ct_leaders_service.delete(l)
            print("Removed Leader: {}".format(l))
        except Exception as e:
            print("Leader delete error: {}".format(e))
    # -------------------------------------------------
    # Clean-up Demo accounts (lookup by ClientId)
    # -------------------------------------------------
    accts = yield mt_accounts_service.find_by_client_id(client_id)
    for a in accts:
        try:
            yield mt_accounts_service.delete(a)
            print("Removed Account: {}".format(a))
        except Exception as e:
            print("Account delete error: {}".format(e))
def ct_demo_create_mt_acct(client_id, broker="demo1-amsterdam.fxpro.com", acct_number=6796186, passwd="dpkk4hg"):
    # -------------------------------------------------
    # Create MT4 account
    # -------------------------------------------------
    acct = yield mt_accounts_service.create({
        'ClientId': client_id,
        'Broker': broker,
        'AccountNumber': acct_number,
        'Password': passwd
    })
    print("Created Account: {}".format(acct))
    # -------------------------------------------------
    # Wait for account to be verified
    # -------------------------------------------------
    acct = yield mt_accounts_service.find_by_id(acct["Id"])
    while not acct["VerificationInfo"]["IsVerified"]:
        print("Waiting for account verification: {}".format(acct["VerificationInfo"]))
        yield sleep(2)
        acct = yield mt_accounts_service.find_by_id(acct["Id"])
    #
    print("Account verified: {}".format(acct["VerificationInfo"]))
    if acct["VerificationInfo"]["VerificationStatus"] != 2:
        raise Exception("Account not valid: {}".format(acct["VerificationInfo"]["VerificationMessage"]))
    return acct
def ct_demo_register_leader_acct(client_id, acct):
    print("-" * 32)
    # -------------------------------------------------
    # Get account's symbols
    # -------------------------------------------------
    symbols = yield mt_accounts_service.get_symbols(acct)
    for s in symbols[-10:]:
        print("Symbol: {}".format(s))
    print("-" * 32)
    # -------------------------------------------------
    # Create Leader account
    # -------------------------------------------------
    leader = yield ct_leaders_service.create(
        {
            'ClientId': client_id,
            'MtAccountRef': acct["Id"],
            'Name': "Demo Leader",
            'Description': "Automatically generated leader's account",
            'TradedSymbols': list(map(lambda s: s["Id"], filter(lambda s: s["TradeMode"] == 4, symbols))),
            # mark to copy all symbols that can be traded (TradeMode==4)
            'Status': 1,  # approved
            'SuggestedAmountToInvest': 99,
            'MonthlySubscriptionFee': {'Amount': 5}
        })
    print("Created Leader: {}".format(leader))
    return leader
def ct_demo_find_mt_acct(client_id, acct_no=6796186):
    acct = None
    accts = yield mt_accounts_service.find_by_client_id(client_id)
    for a in accts:
        if a['AccountNumber'] == acct_no:
            acct = a
            break
    print("Found Account: {}".format(acct))
    if acct is None:
        raise Exception("Demo account not found")
    return acct
def ct_demo_global_lookups():
    print("All system accounts lookup:")
    all_accounts = yield mt_accounts_service.find_all()
    for a in all_accounts:
        print("{}".format(a))
    print("All system leaders lookup:")
    all_leaders = yield ct_leaders_service.find_all()
    for l in all_leaders:
        print("{}".format(l))
    print("All system followers lookup:")
    all_followers = yield ct_followers_service.find_all()
    for f in all_followers:
        print("{}".format(f))