private static async Task Execute(string settingsFilePath)
        {
            if (!File.Exists(settingsFilePath))
            {
                Console.WriteLine($"{settingsFilePath} file not exist");

                return;
            }

            var settings = new FileSettingsReader <ToolSettings>(settingsFilePath);

            var logFactory = LogFactory.Create()
                             .AddConsole();

            var assetServce = new AssetsService(new Uri(settings.CurrentValue.AssetServiceUrl));

            var retryPolicy = Policy.Handle <RetryNeededException>()
                              .WaitAndRetryAsync(10, retryAttempt => TimeSpan.FromSeconds(retryAttempt), onRetry:
                                                 (ex, delay, context, tsk) =>
            {
                Console.WriteLine($"Retrying exception {ex.ToAsyncString()}");
            });

            var clientAccountService = new Lazy <ClientAccountClient>(() =>
                                                                      new ClientAccountClient(settings.CurrentValue.ClientAccountUrl
                                                                                              ?? throw new ArgumentNullException(settings.CurrentValue.ClientAccountUrl)));

            IEnumerable <Asset> assets;

            if (!string.IsNullOrEmpty(settings.CurrentValue.AssetId))
            {
                var asset = await assetServce.AssetGetAsync(settings.CurrentValue.AssetId);

                if (asset == null)
                {
                    Console.WriteLine($"Asset not found {settings.CurrentValue.AssetId}");

                    return;
                }

                assets = new []
                {
                    asset
                };
            }
            else
            {
                assets = await assetServce.AssetGetAllAsync();
            }

            var balanceReaders = BalanceReaderFactory.GetBalanceReaders(assetServce, settings.CurrentValue).ToArray();

            const string csvDeliminator = ";";
            string       header         = $"ClientId;Address;Amount;AssetId;ReceivedAmount;SpentAmount;TransactionsCount{Environment.NewLine}";
            await File.AppendAllTextAsync(settings.CurrentValue.ResultFilePath, header);

            var    counter                 = 0;
            string continuationToken       = null;
            var    relatedAssetsDictionary = new ConcurrentDictionary <Type, IEnumerable <Asset> >();

            do
            {
                IEnumerable <string> clientIds;

                if (string.IsNullOrEmpty(settings.CurrentValue.ClientIdsFilePath))
                {
                    Console.WriteLine("Retrieving client ids batch");
                    var response = await clientAccountService.Value.GetIdsAsync(continuationToken);

                    continuationToken = response.ContinuationToken;
                    clientIds         = response.Ids;
                }
                else
                {
                    clientIds = await File.ReadAllLinesAsync(settings.CurrentValue.ClientIdsFilePath);
                }

                if (string.IsNullOrEmpty(settings.CurrentValue.AssetId) && settings.CurrentValue.IncludeZeroBalances)
                {
                    throw new ArgumentException("If AssetId is omitted, IncludeZeroBalances should be false.");
                }

                foreach (var clientId in clientIds)
                {
                    IEnumerable <(IBalanceReader balanceReader, string address)> addresses;

                    switch (settings.CurrentValue.WalletType)
                    {
                    case WalletTypes.Private:
                        addresses = await GetPrivateWalletAddresses(clientId,
                                                                    logFactory,
                                                                    settings,
                                                                    balanceReaders);

                        break;

                    case WalletTypes.Deposit:
                        addresses = await GetDepositWallets(clientId,
                                                            logFactory,
                                                            settings,
                                                            balanceReaders);

                        break;

                    default:
                        throw new ArgumentException("Unknown switch", nameof(ToolSettings.WalletType));
                    }

                    foreach (var balanceReaderAddresses in addresses.GroupBy(p => p.balanceReader.GetType()))
                    {
                        var balanceReader = balanceReaderAddresses.First().balanceReader;

                        //cache enumeration
                        var relatedAssets = relatedAssetsDictionary.GetOrAdd(balanceReader.GetType(),
                                                                             (type) => balanceReader.SelectRelatedAssetsAsync(assets).Result.ToList());

                        foreach (var address in balanceReader.SelectUniqueAddresses(balanceReaderAddresses.Select(p => p.address)))
                        {
                            try
                            {
                                var blockchainBalances = await retryPolicy.ExecuteAsync(
                                    () => balanceReader.ReadBalance(relatedAssets, address));

                                var transactionsInfo = await retryPolicy.ExecuteAsync(
                                    () => balanceReader.GetTransactionsInfoAsync(relatedAssets, address, settings.CurrentValue.AssetId, settings.CurrentValue.PrivateWalletsCount.FromDate,
                                                                                 settings.CurrentValue.PrivateWalletsCount.FromBlock));

                                foreach (var blockchainBalance in blockchainBalances
                                         .Where(p => p.amount != 0 || settings.CurrentValue.IncludeZeroBalances))
                                {
                                    await File.AppendAllTextAsync(settings.CurrentValue.ResultFilePath,
                                                                  string.Join(csvDeliminator,
                                                                              clientId,
                                                                              blockchainBalance.address,
                                                                              blockchainBalance.amount.ToString(CultureInfo.InvariantCulture),
                                                                              blockchainBalance.assetId,
                                                                              transactionsInfo.AssetId == blockchainBalance.assetId ? transactionsInfo.ReceivedAmount.ToString(CultureInfo.InvariantCulture) : "-",
                                                                              transactionsInfo.AssetId == blockchainBalance.assetId ? transactionsInfo.SpentAmount.ToString(CultureInfo.InvariantCulture) : "-",
                                                                              transactionsInfo.AssetId == blockchainBalance.assetId ? transactionsInfo.TransactionsCount.ToString(CultureInfo.InvariantCulture) : "-"
                                                                              )
                                                                  + Environment.NewLine);
                                }
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine($"Exception during processing balance for client {clientId}, address: {address}: {e.ToAsyncString()}");

                                await File.AppendAllTextAsync(settings.CurrentValue.ErrorFilePath,
                                                              string.Join(csvDeliminator,
                                                                          DateTime.UtcNow,
                                                                          clientId,
                                                                          address,
                                                                          e.ToAsyncString())
                                                              + Environment.NewLine);
                            }
                        }
                    }

                    counter++;
                    Console.WriteLine($"[{DateTime.UtcNow}] {clientId} done -- {counter}");
                }
            } while (continuationToken != null);

            Console.WriteLine("All done");
        }