Package: metaapi-cloud-copyfactory-sdk
CopyFactory is a powerful trade copying API which makes developing forex
trade copying applications as easy as writing few lines of code.CopyFactory API is a member of MetaApi project (https://metaapi.cloud),
a powerful cloud forex trading API which supports both MetaTrader 4 and MetaTrader 5 platforms.MetaApi is a paid service, however we offer a free tier for testing and personal use.TheMetaApi pricingwas developed with the intent to make your charges less or equal to what you would have to pay
for hosting your own infrastructure. This is possible because over time we managed to heavily optimize
our MetaTrader infrastructure. And with MetaApi you can save significantly on application development and
maintenance costs and time thanks to high-quality API, open-source SDKs and convenience of a cloud service.This SDK requires a 3.8+ version of Python to run.Why do we offer CopyFactory API trade copying APIWe found that developing reliable and flexible trade copier is a task
which requires lots of effort, because developers have to solve a series
of complex technical tasks to create a product.We decided to share our product as it allows developers to start with a
powerful solution in almost no time, saving on development and
infrastructure maintenance costs.Frequently asked questions (FAQ)FAQ is located here:https://metaapi.cloud/docs/copyfactory/faq/CopyFactory copytrading API featuresFeatures supported:low latency trade copying APIreliable trade copying APIsuitable for large-scale deploymentssuitable for large number of subscribersconnect arbitrary number of strategy providers and subscriberssubscribe accounts to multiple strategies at onceselect arbitrary copy ratio for each subscriptionconfigure symbol mapping between strategy providers and subscribersapply advanced risk filters on strategy provider sideoverride risk filters on subscriber sideprovide multiple strategies from a single account based on magic or symbol filterssupports manual trading on subscriber accounts while copying tradessynchronize subscriber account with strategy providersmonitor trading historycalculate trade copying commissions for account managerssupport portfolio strategies as trading signal source, i.e. the strategies which include signals of several other strategies (also known as combos on some platforms)Please note that trade copying to MT5 netting accounts is not supported in the current API versionPlease check Features section of thehttps://metaapi.cloud/docs/copyfactory/documentation for detailed description of all settings you can make.REST API documentationCopyFactory SDK is built on top of CopyFactory REST API.CopyFactory REST API docs are available athttps://metaapi.cloud/docs/copyfactory/Code examplesWe published some code examples in our github repository, namely:Python:https://github.com/metaapi/metaapi-copyfactory-python-sdk/tree/master/examplesInstallationpipinstallmetaapi-cloud-sdkRetrieving API tokenPlease visithttps://app.metaapi.cloud/tokenweb UI to obtain your API token.Configuring trade copyingIn order to configure trade copying you need to:add MetaApi MetaTrader accounts with CopyFactory as application field value (see above)create CopyFactory master and slave accounts and connect them to MetaApi accounts via connectionId fieldcreate a strategy being copiedsubscribe slave CopyFactory accounts to the strategyfrommetaapi_cloud_sdkimportMetaApi,CopyFactorytoken='...'metaapi=MetaApi(token=token)copy_factory=CopyFactory(token=token)# retrieve MetaApi MetaTrader accounts with CopyFactory as application field value# master account must have PROVIDER value in copyFactoryRolesmaster_metaapi_account=awaitmetaapi.metatrader_account_api.get_account(account_id='masterMetaapiAccountId')if(master_metaapi_accountisNone)ormaster_metaapi_account.copy_factory_rolesisNoneor'PROVIDER'not\inmaster_metaapi_account.copy_factory_roles:raiseException('Please specify PROVIDER copyFactoryRoles value in your MetaApi ''account in order to use it in CopyFactory API')# slave account must have SUBSCRIBER value in copyFactoryRolesslave_metaapi_account=awaitmetaapi.metatrader_account_api.get_account(account_id='slaveMetaapiAccountId')if(slave_metaapi_accountisNone)orslave_metaapi_account.copy_factory_rolesisNoneor'SUBSCRIBER'not\inslave_metaapi_account.copy_factory_roles:raiseException('Please specify SUBSCRIBER copyFactoryRoles value in your MetaApi ''account in order to use it in CopyFactory API')configuration_api=copy_factory.configuration_api# create a strategy being copiedstrategy_id=awaitconfiguration_api.generate_strategy_id()awaitconfiguration_api.update_strategy(id=strategy_id['id'],strategy={'name':'Test strategy','description':'Some useful description about your strategy','accountId':master_metaapi_account.id,'maxTradeRisk':0.1,'stopOutRisk':{'value':0.4,'startTime':'2020-08-24T00:00:00.000Z'},'timeSettings':{'lifetimeInHours':192,'openingIntervalInMinutes':5}})# subscribe slave CopyFactory accounts to the strategyawaitconfiguration_api.update_subscriber(slave_metaapi_account.id,{'name':'Demo account','subscriptions':[{'strategyId':strategy_id['id'],'multiplier':1}]})See in-code documentation for full definition of possible configuration options.Retrieving paginated listsThere are two groups of methods to retrieve paginated lists:with pagination in infinite scroll stylewith pagination in a classic style which allows you to calculate page countThey are applied to following entities:strategies:get_strategies_with_infinite_scroll_paginationandget_strategies_with_classic_paginationprovider portfolios:get_portfolio_strategies_with_infinite_scroll_paginationandget_portfolio_strategies_with_classic_paginationsubscribers:get_subscribers_with_infinite_scroll_paginationandget_subscribers_with_classic_paginationExample of retrieving strategies with pagination in infinite scroll style:# paginate strategies, see in-code documentation for full list of filter options available.strategies=awaitapi.metatrader_account_api.get_strategies_with_infinite_scroll_pagination({'limit':10,'offset':0})# get strategies without filter (returns 1000 strategies max)strategies=awaitapi.metatrader_account_api.get_strategies_with_infinite_scroll_pagination()strategy=Noneforsinstrategies:ifs['_id']=='strategyId':strategy=sbreakExample of retrieving strategies with pagination in classic style:# paginate strategies, see in-code documentation for full list of filter options available.strategies=awaitapi.metatrader_account_api.get_strategies_with_classic_pagination({'limit':10,'offset':0})strategy=Noneforsinstrategies:ifs['_id']=='strategyId':strategy=sbreak# number of all strategies matching filter without pagination optionsprint(strategies['count'])# get strategies without filter (returns 1000 strategies max)strategies=awaitapi.metatrader_account_api.get_strategies_with_classic_pagination()Retrieving trade copying historyCopyFactory allows you to monitor transactions conducted on trading accounts in real time.Retrieving trading history on provider sidehistory_api=copy_factory.history_api# retrieve trading history, please note that this method support pagination and limits number of recordsprint(awaithistory_api.get_provided_transactions(time_from=datetime.fromisoformat('2020-08-01'),time_till=datetime.fromisoformat('2020-09-01')))Retrieving trading history on subscriber sidehistory_api=copy_factory.history_api# retrieve trading history, please note that this method support pagination and limits number of recordsprint(awaithistory_api.get_subscription_transactions(time_from=datetime.fromisoformat('2020-08-01'),time_till=datetime.fromisoformat('2020-09-01')))Resynchronizing slave accounts to mastersThere is a configurable time limit during which the trades can be opened. Sometimes trades can not open in time due to broker errors or trading session time discrepancy.
You can resynchronize a slave account to place such late trades. Please note that positions which were
closed manually on a slave account will also be reopened during resynchronization.account_id='...'# CopyFactory account id# resynchronize all strategiesawaitcopy_factory.trading_api.resynchronize(account_id=account_id)# resynchronize specific strategyawaitcopy_factory.trading_api.resynchronize(account_id=account_id,strategy_ids=['ABCD'])Sending external trading signals to a strategyYou can submit external trading signals to your trading strategy.trading_api=copy_factory.trading_apisignal_id=trading_api.generate_signal_id()# get signal clientsignal_client=awaittrading_api.get_signal_client(account_id=account_id)# add trading signalawaitsignal_client.update_external_signal(strategy_id=strategy_id,signal_id=signal_id,signal={'symbol':'EURUSD','type':'POSITION_TYPE_BUY','time':datetime.now(),'volume':0.01})# get external signalsprint(awaitsignal_client.get_strategy_external_signals(strategy_id))# remove signalawaitsignal_client.remove_external_signal(strategy_id=strategy_id,signal_id=signal_id,signal={'time':datetime.now()})Retrieving trading signalssubscriber_id='...'# CopyFactory subscriber idsignal_client=awaittrading_api.get_signal_client(account_id=account_id)# retrieve trading signalsprint(awaitsignal_client.get_trading_signals(subscriber_id))Managing stopoutsA subscription to a strategy can be stopped if the strategy have exceeded allowed risk limit.trading_api=copy_factory.trading_apiaccount_id='...'# CopyFactory account idstrategy_id='...'# CopyFactory strategy id# retrieve list of strategy stopoutsprint(awaittrading_api.get_stopouts(account_id=account_id))# reset a stopout so that subscription can continueawaittrading_api.reset_subscription_stopouts(account_id=account_id,strategy_id=strategy_id,reason='daily-equity')Managing stopout listenersYou can subscribe to a stream of stopout events using the stopout listener.frommetaapi_cloud_sdkimportStopoutListenertrading_api=copy_factory.trading_api# create a custom class based on the StopoutListenerclassListener(StopoutListener):# specify the function called on event arrivalasyncdefon_stopout(self,strategy_stopout_event):print('Strategy stopout event',strategy_stopout_event)# specify the function called on error eventasyncdefon_error(self,error):print('Error event',error)# add listenerlistener=Listener()listener_id=trading_api.add_stopout_listener(listener)# remove listenertrading_api.remove_stopout_listener(listener_id)Retrieving slave trading logstrading_api=copy_factory.trading_apiaccount_id='...'# CopyFactory account id# retrieve slave trading logprint(awaittrading_api.get_user_log(account_id))# retrieve paginated slave trading log by time rangeprint(awaittrading_api.get_user_log(account_id,datetime.fromtimestamp(datetime.now().timestamp()-24*60*60),None,20,10))Log streamingYou can subscribe to a stream of strategy or subscriber log events using the user log listener.Strategy logsfrommetaapi_cloud_sdkimportUserLogListenertrading_api=copy_factory.trading_api# create a custom class based on the UserLogListenerclassListener(UserLogListener):# specify the function called on event arrivalasyncdefon_user_log(self,log_event):print('Strategy user log event',log_event)# specify the function called on error eventasyncdefon_error(self,error):print('Error event',error)# add listenerlistener=Listener()listener_id=trading_api.add_strategy_log_listener(listener,'ABCD')# remove listenertrading_api.remove_strategy_log_listener(listener_id)Subscriber logsfrommetaapi_cloud_sdkimportUserLogListenertrading_api=copy_factory.trading_api# create a custom class based on the UserLogListenerclassListener(UserLogListener):# specify the function called on event arrivalasyncdefon_user_log(self,log_event):print('Subscriber user log event',log_event)# specify the function called on error eventasyncdefon_error(self,error):print('Error event',error)# add listenerlistener=Listener()listener_id=trading_api.add_subscriber_log_listener(listener,'accountId')# remove listenertrading_api.remove_subscriber_log_listener(listener_id)Transaction streamingYou can subscribe to a stream of strategy or subscriber transaction events using the transaction listener.Strategy transactionsfrommetaapi_cloud_sdkimportTransactionListenerhistory_api=copy_factory.history_api# create a custom class based on the TransactionListenerclassListener(TransactionListener):# specify the function called on event arrivalasyncdefon_transaction(self,transaction_event):print('Strategy transaction event',transaction_event)# specify the function called on error eventasyncdefon_error(self,error):print('Error event',error)# add listenerlistener=Listener()listener_id=history_api.add_strategy_transaction_listener(listener,'ABCD')# remove listenerhistory_api.remove_strategy_transaction_listener(listener_id)Subscriber transactionsfrommetaapi_cloud_sdkimportTransactionListenerhistory_api=copy_factory.history_api# create a custom class based on the TransactionListenerclassListener(TransactionListener):# specify the function called on event arrivalasyncdefon_transaction(transaction_event):print('Subscriber transaction event',transaction_event)# specify the function called on error eventasyncdefon_error(self,error):print('Error event',error)# add listenerlistener=Listener()listener_id=history_api.add_strategy_transaction_listener(listener,'ABCD')# remove listenerhistory_api.remove_subscriber_transaction_listener(listener_id)Related projects:See our website for the full list of APIs and features supportedhttps://metaapi.cloud/#featuresSome of the APIs you might decide to use together with this module:MetaApi cloud forex trading APIhttps://metaapi.cloud/docs/client/MetaTrader account management APIhttps://metaapi.cloud/docs/provisioning/MetaStats cloud forex trading statistics APIhttps://metaapi.cloud/docs/metastats/MetaApi MT manager APIhttps://metaapi.cloud/docs/manager/MetaApi risk management APIhttps://metaapi.cloud/docs/risk-management/