Compare commits

...

6 Commits
16188 ... 11368

Author SHA1 Message Date
Martin-Molinero
d94a1d09a4 Remove unrequired references 2021-04-12 16:05:01 -03:00
Martin-Molinero
2c843cae9e Fix rebase
- Fix ambiguous Index
- Remove StrategyCapacity.cs
- Update System.Threading.Tasks.Extensionsy
2021-04-12 15:09:34 -03:00
Stefano Raggi
039fdf7e4a Upgrade IBAutomater to v1.0.51
ignored, and an empty message aborts the commit.
2021-04-12 15:09:33 -03:00
Martin Molinero
2c63546c37 Remove FXCM 2021-04-12 15:09:33 -03:00
Martin Molinero
58682e1bbd Fix ambiguous errors. Add IBAutomator net5 2021-04-12 15:09:33 -03:00
Gerardo Salazar
d11a375fdb Update projects to use .NET 5.0, the successor to .NET Core 2021-04-12 15:09:33 -03:00
56 changed files with 35 additions and 4304 deletions

View File

@@ -79,19 +79,19 @@ namespace QuantConnect.Algorithm.CSharp
// things like manually added, auto added, internal, and any other boolean state we need to track against a single security)
throw new Exception("The underlying equity data should NEVER be removed in this algorithm because it was manually added");
}
if (_expectedSecurities.AreDifferent(LinqExtensions.ToHashSet(Securities.Keys)))
if (_expectedSecurities.AreDifferent(Securities.Keys.ToHashSet()))
{
var expected = string.Join(Environment.NewLine, _expectedSecurities.OrderBy(s => s.ToString()));
var actual = string.Join(Environment.NewLine, Securities.Keys.OrderBy(s => s.ToString()));
throw new Exception($"{Time}:: Detected differences in expected and actual securities{Environment.NewLine}Expected:{Environment.NewLine}{expected}{Environment.NewLine}Actual:{Environment.NewLine}{actual}");
}
if (_expectedUniverses.AreDifferent(LinqExtensions.ToHashSet(UniverseManager.Keys)))
if (_expectedUniverses.AreDifferent(Securities.Keys.ToHashSet()))
{
var expected = string.Join(Environment.NewLine, _expectedUniverses.OrderBy(s => s.ToString()));
var actual = string.Join(Environment.NewLine, UniverseManager.Keys.OrderBy(s => s.ToString()));
throw new Exception($"{Time}:: Detected differences in expected and actual universes{Environment.NewLine}Expected:{Environment.NewLine}{expected}{Environment.NewLine}Actual:{Environment.NewLine}{actual}");
}
if (_expectedData.AreDifferent(LinqExtensions.ToHashSet(data.Keys)))
if (_expectedData.AreDifferent(Securities.Keys.ToHashSet()))
{
var expected = string.Join(Environment.NewLine, _expectedData.OrderBy(s => s.ToString()));
var actual = string.Join(Environment.NewLine, data.Keys.OrderBy(s => s.ToString()));
@@ -183,7 +183,7 @@ namespace QuantConnect.Algorithm.CSharp
if (changes.RemovedSecurities
.Where(x => x.Symbol.SecurityType == SecurityType.Option)
.ToHashSet(s => s.Symbol)
.AreDifferent(LinqExtensions.ToHashSet(_expectedContracts)))
.AreDifferent(_expectedContracts.ToHashSet()))
{
throw new Exception("Expected removed securities to equal expected contracts added");
}

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Algorithm.CSharp</RootNamespace>
<AssemblyName>QuantConnect.Algorithm.CSharp</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>6</LangVersion>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
@@ -63,10 +63,6 @@
<PackageReference Include="NodaTime" Version="3.0.5" />
<PackageReference Include="R.NET" Version="1.9.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Algorithm.Framework</RootNamespace>
<AssemblyName>QuantConnect.Algorithm.Framework</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
@@ -54,10 +54,6 @@
</PackageReference>
<PackageReference Include="NodaTime" Version="3.0.5" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Algorithm.Python</RootNamespace>
<AssemblyName>QuantConnect.Algorithm.Python</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>6</LangVersion>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<OutputPath>bin\$(Configuration)\</OutputPath>

View File

@@ -45,8 +45,8 @@ using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Algorithm.Selection;
using QuantConnect.Securities.Index;
using QuantConnect.Storage;
using Index = QuantConnect.Securities.Index.Index;
namespace QuantConnect.Algorithm
{

View File

@@ -5,7 +5,7 @@
<ProductVersion>8.0.30703</ProductVersion>
<RootNamespace>QuantConnect.Algorithm</RootNamespace>
<AssemblyName>QuantConnect.Algorithm</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<LangVersion>6</LangVersion>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
@@ -64,10 +64,6 @@
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NodaTime" Version="3.0.5" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.AlgorithmFactory</RootNamespace>
<AssemblyName>QuantConnect.AlgorithmFactory</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>6</LangVersion>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
@@ -48,10 +48,6 @@
</PackageReference>
<PackageReference Include="NodaTime" Version="3.0.5" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -5,7 +5,7 @@
<ProductVersion>8.0.30703</ProductVersion>
<RootNamespace>QuantConnect.Api</RootNamespace>
<AssemblyName>QuantConnect.Api</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<LangVersion>6</LangVersion>
@@ -58,12 +58,6 @@
<PackageReference Include="RestSharp" Version="106.6.10" />
<PackageReference Include="SharpZipLib" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Configuration" />
<Reference Include="System.Web" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -1,148 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using com.fxcm.fix;
using com.fxcm.fix.pretrade;
using NodaTime;
using QuantConnect.Data;
using QuantConnect.Logging;
using QuantConnect.Packets;
using QuantConnect.Securities;
namespace QuantConnect.Brokerages.Fxcm
{
/// <summary>
/// FXCM brokerage - implementation of IDataQueueHandler interface
/// </summary>
public partial class FxcmBrokerage
{
#region IDataQueueHandler implementation
/// <summary>
/// Sets the job we're subscribing for
/// </summary>
/// <param name="job">Job we're subscribing for</param>
public void SetJob(LiveNodePacket job)
{
}
/// <summary>
/// Subscribe to the specified configuration
/// </summary>
/// <param name="dataConfig">defines the parameters to subscribe to a data feed</param>
/// <param name="newDataAvailableHandler">handler to be fired on new data available</param>
/// <returns>The new enumerator for this subscription request</returns>
public IEnumerator<BaseData> Subscribe(SubscriptionDataConfig dataConfig, EventHandler newDataAvailableHandler)
{
if (!CanSubscribe(dataConfig.Symbol))
{
return Enumerable.Empty<BaseData>().GetEnumerator();
}
var enumerator = _aggregator.Add(dataConfig, newDataAvailableHandler);
_subscriptionManager.Subscribe(dataConfig);
return enumerator;
}
/// <summary>
/// Adds the specified symbols to the subscription
/// </summary>
/// <param name="symbols">The symbols to be added keyed by SecurityType</param>
private bool Subscribe(IEnumerable<Symbol> symbols)
{
var request = new MarketDataRequest();
foreach (var symbol in symbols)
{
TradingSecurity fxcmSecurity;
if (_fxcmInstruments.TryGetValue(_symbolMapper.GetBrokerageSymbol(symbol), out fxcmSecurity))
{
request.addRelatedSymbol(fxcmSecurity);
// cache exchange time zone for symbol
DateTimeZone exchangeTimeZone;
if (!_symbolExchangeTimeZones.TryGetValue(symbol, out exchangeTimeZone))
{
exchangeTimeZone = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.FXCM, symbol, symbol.SecurityType).TimeZone;
_symbolExchangeTimeZones.Add(symbol, exchangeTimeZone);
}
}
}
request.setSubscriptionRequestType(SubscriptionRequestTypeFactory.SUBSCRIBE);
request.setMDEntryTypeSet(MarketDataRequest.MDENTRYTYPESET_ALL);
lock (_locker)
{
_gateway.sendMessage(request);
}
return true;
}
/// <summary>
/// Removes the specified configuration
/// </summary>
/// <param name="dataConfig">Subscription config to be removed</param>
public void Unsubscribe(SubscriptionDataConfig dataConfig)
{
_subscriptionManager.Unsubscribe(dataConfig);
_aggregator.Remove(dataConfig);
}
/// <summary>
/// Removes the specified symbols to the subscription
/// </summary>
/// <param name="symbols">The symbols to be removed keyed by SecurityType</param>
private bool Unsubscribe(IEnumerable<Symbol> symbols)
{
Log.Trace("FxcmBrokerage.Unsubscribe(): {0}", string.Join(",", symbols));
var request = new MarketDataRequest();
foreach (var symbol in symbols)
{
request.addRelatedSymbol(_fxcmInstruments[_symbolMapper.GetBrokerageSymbol(symbol)]);
}
request.setSubscriptionRequestType(SubscriptionRequestTypeFactory.UNSUBSCRIBE);
request.setMDEntryTypeSet(MarketDataRequest.MDENTRYTYPESET_ALL);
lock (_locker)
{
_gateway.sendMessage(request);
}
return true;
}
/// <summary>
/// Returns true if this brokerage supports the specified symbol
/// </summary>
private static bool CanSubscribe(Symbol symbol)
{
// ignore unsupported security types
if (symbol.ID.SecurityType != SecurityType.Forex && symbol.ID.SecurityType != SecurityType.Cfd)
return false;
// ignore universe symbols
return !symbol.Value.Contains("-UNIVERSE-");
}
#endregion
}
}

View File

@@ -1,548 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using com.fxcm.external.api.transport;
using com.fxcm.fix;
using com.fxcm.fix.admin;
using com.fxcm.fix.other;
using com.fxcm.fix.posttrade;
using com.fxcm.fix.pretrade;
using com.fxcm.fix.trade;
using com.fxcm.messaging;
using NodaTime;
using QuantConnect.Data.Market;
using QuantConnect.Logging;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
namespace QuantConnect.Brokerages.Fxcm
{
/// <summary>
/// FXCM brokerage - Java API related functions and interface implementations
/// </summary>
public partial class FxcmBrokerage
{
private IGateway _gateway;
private readonly object _locker = new object();
private string _currentRequest;
private const int ResponseTimeout = 5000;
private bool _isOrderUpdateOrCancelRejected;
private bool _isOrderSubmitRejected;
private readonly Dictionary<string, TradingSecurity> _fxcmInstruments = new Dictionary<string, TradingSecurity>();
private readonly Dictionary<string, CollateralReport> _accounts = new Dictionary<string, CollateralReport>();
private readonly Dictionary<string, MarketDataSnapshot> _rates = new Dictionary<string, MarketDataSnapshot>();
private readonly Dictionary<string, ExecutionReport> _openOrders = new Dictionary<string, ExecutionReport>();
// Map key: fxcmPositionId (can have multiple positions for the same symbol)
private readonly Dictionary<string, PositionReport> _openPositions = new Dictionary<string, PositionReport>();
private readonly Dictionary<string, Order> _mapRequestsToOrders = new Dictionary<string, Order>();
private readonly Dictionary<string, Order> _mapFxcmOrderIdsToOrders = new Dictionary<string, Order>();
private readonly Dictionary<string, AutoResetEvent> _mapRequestsToAutoResetEvents = new Dictionary<string, AutoResetEvent>();
private readonly HashSet<string> _pendingHistoryRequests = new HashSet<string>();
private void LoadInstruments()
{
// Note: requestTradingSessionStatus() MUST be called just after login
AutoResetEvent autoResetEvent;
lock (_locker)
{
_currentRequest = _gateway.requestTradingSessionStatus();
autoResetEvent = new AutoResetEvent(false);
_mapRequestsToAutoResetEvents[_currentRequest] = autoResetEvent;
}
if (!autoResetEvent.WaitOne(ResponseTimeout))
throw new TimeoutException("FxcmBrokerage.LoadInstruments(): Operation took longer than " +
$"{((decimal)ResponseTimeout / 1000).ToStringInvariant()} seconds."
);
}
private void LoadAccounts()
{
AutoResetEvent autoResetEvent;
lock (_locker)
{
_currentRequest = _gateway.requestAccounts();
autoResetEvent = new AutoResetEvent(false);
_mapRequestsToAutoResetEvents[_currentRequest] = autoResetEvent;
}
if (!autoResetEvent.WaitOne(ResponseTimeout))
throw new TimeoutException("FxcmBrokerage.LoadAccounts(): Operation took longer than " +
$"{((decimal)ResponseTimeout / 1000).ToStringInvariant()} seconds."
);
if (!_accounts.ContainsKey(_accountId))
throw new ArgumentException("FxcmBrokerage.LoadAccounts(): The account id is invalid: " + _accountId);
// Hedging MUST be disabled on the account
if (_accounts[_accountId].getParties().getFXCMPositionMaintenance() == "Y")
{
throw new NotSupportedException("FxcmBrokerage.LoadAccounts(): The Lean engine does not support accounts with Hedging enabled. " +
"Please contact FXCM Active Trader support to disable Hedging. They can be reached at https://www.fxcm.com/markets/contact-client-support/ through their Live Chat or Phone."
);
}
}
private void LoadOpenOrders()
{
AutoResetEvent autoResetEvent;
lock (_locker)
{
_currentRequest = _gateway.requestOpenOrders(null);
autoResetEvent = new AutoResetEvent(false);
_mapRequestsToAutoResetEvents[_currentRequest] = autoResetEvent;
}
if (!autoResetEvent.WaitOne(ResponseTimeout))
throw new TimeoutException("FxcmBrokerage.LoadOpenOrders(): Operation took longer than " +
$"{((decimal)ResponseTimeout / 1000).ToStringInvariant()} seconds."
);
}
private void LoadOpenPositions()
{
AutoResetEvent autoResetEvent;
lock (_locker)
{
_currentRequest = _terminal.Equals("Demo") ?
_gateway.requestOpenPositions(_accountId.ConvertInvariant<long>()) :
_gateway.requestOpenPositions(_accountId);
autoResetEvent = new AutoResetEvent(false);
_mapRequestsToAutoResetEvents[_currentRequest] = autoResetEvent;
}
if (!autoResetEvent.WaitOne(ResponseTimeout))
throw new TimeoutException("FxcmBrokerage.LoadOpenPositions(): Operation took longer than " +
$"{((decimal)ResponseTimeout / 1000).ToStringInvariant()} seconds."
);
}
/// <summary>
/// Provides as public access to this data without requiring consumers to reference
/// IKVM libraries
/// </summary>
public List<Tick> GetBidAndAsk(List<string> fxcmSymbols)
{
return GetQuotes(fxcmSymbols).Select(x => new Tick
{
Symbol = _symbolMapper.GetLeanSymbol(
x.getInstrument().getSymbol(),
_symbolMapper.GetBrokerageSecurityType(x.getInstrument().getSymbol()),
Market.FXCM),
BidPrice = (decimal)x.getBidClose(),
AskPrice = (decimal)x.getAskClose()
}).ToList();
}
/// <summary>
/// Gets the quotes for the symbol
/// </summary>
private List<MarketDataSnapshot> GetQuotes(List<string> fxcmSymbols)
{
// get current quotes for the instrument
var request = new MarketDataRequest();
request.setMDEntryTypeSet(MarketDataRequest.MDENTRYTYPESET_ALL);
request.setSubscriptionRequestType(SubscriptionRequestTypeFactory.SNAPSHOT);
foreach (var fxcmSymbol in fxcmSymbols)
{
request.addRelatedSymbol(_fxcmInstruments[fxcmSymbol]);
}
AutoResetEvent autoResetEvent;
lock (_locker)
{
_currentRequest = _gateway.sendMessage(request);
autoResetEvent = new AutoResetEvent(false);
_mapRequestsToAutoResetEvents[_currentRequest] = autoResetEvent;
}
if (!autoResetEvent.WaitOne(ResponseTimeout))
throw new TimeoutException("FxcmBrokerage.GetQuotes(): Operation took longer than " +
$"{((decimal)ResponseTimeout / 1000).ToStringInvariant()} seconds."
);
return _rates.Where(x => fxcmSymbols.Contains(x.Key)).Select(x => x.Value).ToList();
}
#region IGenericMessageListener implementation
/// <summary>
/// Receives generic messages from the FXCM API
/// </summary>
/// <param name="message">Generic message received</param>
public void messageArrived(ITransportable message)
{
// Dispatch message to specific handler
lock (_locker)
{
if (message is TradingSessionStatus)
OnTradingSessionStatus((TradingSessionStatus)message);
else if (message is CollateralReport)
OnCollateralReport((CollateralReport)message);
else if (message is MarketDataSnapshot)
OnMarketDataSnapshot((MarketDataSnapshot)message);
else if (message is ExecutionReport)
OnExecutionReport((ExecutionReport)message);
else if (message is RequestForPositionsAck)
OnRequestForPositionsAck((RequestForPositionsAck)message);
else if (message is PositionReport)
OnPositionReport((PositionReport)message);
else if (message is OrderCancelReject)
OnOrderCancelReject((OrderCancelReject)message);
else if (message is UserResponse || message is CollateralInquiryAck || message is Logout ||
message is MarketDataRequestReject || message is BusinessMessageReject || message is SecurityStatus)
{
// Unused messages, no handler needed
}
else
{
// Should never get here, if it does log and ignore message
// New messages added in future api updates should be added to the unused list above
Log.Trace("FxcmBrokerage.messageArrived(): Unknown message: {0}", message);
}
}
}
/// <summary>
/// TradingSessionStatus message handler
/// </summary>
private void OnTradingSessionStatus(TradingSessionStatus message)
{
if (message.getRequestID() == _currentRequest)
{
// load instrument list into a dictionary
var securities = message.getSecurities();
while (securities.hasMoreElements())
{
var security = (TradingSecurity)securities.nextElement();
_fxcmInstruments[security.getSymbol()] = security;
}
// get account base currency
AccountBaseCurrency = message.getParameter("BASE_CRNCY").getValue();
_mapRequestsToAutoResetEvents[_currentRequest].Set();
_mapRequestsToAutoResetEvents.Remove(_currentRequest);
}
}
/// <summary>
/// CollateralReport message handler
/// </summary>
private void OnCollateralReport(CollateralReport message)
{
// add the trading account to the account list
_accounts[message.getAccount()] = message;
if (message.getRequestID() == _currentRequest)
{
// set the state of the request to be completed only if this is the last collateral report requested
if (message.isLastRptRequested())
{
_mapRequestsToAutoResetEvents[_currentRequest].Set();
_mapRequestsToAutoResetEvents.Remove(_currentRequest);
}
}
}
/// <summary>
/// MarketDataSnapshot message handler
/// </summary>
private void OnMarketDataSnapshot(MarketDataSnapshot message)
{
var instrument = message.getInstrument();
var securityType = _symbolMapper.GetBrokerageSecurityType(instrument.getSymbol());
var symbol = _symbolMapper.GetLeanSymbol(instrument.getSymbol(), securityType, Market.FXCM);
var isHistoryResponse = _pendingHistoryRequests.Contains(message.getRequestID());
if (isHistoryResponse)
{
var time = FromJavaDate(message.getDate().toDate());
// history timestamps must be in exchange time zone
DateTimeZone exchangeTimeZone;
if (_symbolExchangeTimeZones.TryGetValue(symbol, out exchangeTimeZone))
{
time = time.ConvertFromUtc(exchangeTimeZone);
}
// append ticks/bars to history
if (message.getFXCMTimingInterval() == FXCMTimingIntervalFactory.TICK)
{
var bidPrice = Convert.ToDecimal(message.getBidClose());
var askPrice = Convert.ToDecimal(message.getAskClose());
var tick = new Tick(time, symbol, bidPrice, askPrice);
_lastHistoryChunk.Add(tick);
}
else
{
var bar = new QuoteBar(
time,
symbol,
new Bar(
Convert.ToDecimal(message.getBidOpen()),
Convert.ToDecimal(message.getBidHigh()),
Convert.ToDecimal(message.getBidLow()),
Convert.ToDecimal(message.getBidClose())
),
0,
new Bar(
Convert.ToDecimal(message.getAskOpen()),
Convert.ToDecimal(message.getAskHigh()),
Convert.ToDecimal(message.getAskLow()),
Convert.ToDecimal(message.getAskClose())
),
0);
_lastHistoryChunk.Add(bar);
}
}
else
{
// update the current prices for the instrument
_rates[instrument.getSymbol()] = message;
// if instrument is subscribed, add ticks to list
if (_subscriptionManager.IsSubscribed(symbol, TickType.Quote))
{
// For some unknown reason, messages returned by SubscriptionRequestTypeFactory.SUBSCRIBE
// have message.getDate() rounded to the second, so we use message.getMakingTime() instead
var time = FromJavaDate(new java.util.Date(message.getMakingTime()));
// live ticks timestamps must be in exchange time zone
DateTimeZone exchangeTimeZone;
if (_symbolExchangeTimeZones.TryGetValue(symbol, out exchangeTimeZone))
{
time = time.ConvertFromUtc(exchangeTimeZone);
}
var bidPrice = Convert.ToDecimal(message.getBidClose());
var askPrice = Convert.ToDecimal(message.getAskClose());
var tick = new Tick(time, symbol, bidPrice, askPrice);
_aggregator.Update(tick);
}
}
if (message.getRequestID() == _currentRequest)
{
if (message.getFXCMContinuousFlag() == IFixValueDefs.__Fields.FXCMCONTINUOUS_END)
{
_mapRequestsToAutoResetEvents[_currentRequest].Set();
_mapRequestsToAutoResetEvents.Remove(_currentRequest);
if (isHistoryResponse) _pendingHistoryRequests.Remove(_currentRequest);
}
}
}
/// <summary>
/// ExecutionReport message handler
/// </summary>
private void OnExecutionReport(ExecutionReport message)
{
var orderId = message.getOrderID();
var orderStatus = message.getFXCMOrdStatus();
if (orderId != "NONE" && message.getAccount() == _accountId)
{
if (_openOrders.ContainsKey(orderId) && OrderIsClosed(orderStatus.getCode()))
{
_openOrders.Remove(orderId);
}
else
{
_openOrders[orderId] = message;
}
Order order;
if (_mapFxcmOrderIdsToOrders.TryGetValue(orderId, out order))
{
// existing order
if (!OrderIsBeingProcessed(orderStatus.getCode()))
{
var status = ConvertOrderStatus(orderStatus);
int id;
// if we get a Submitted status and we had placed an order update, this new event is flagged as an update
var isUpdate = status == OrderStatus.Submitted && _orderUpdates.TryRemove(order.Id, out id);
var security = _securityProvider.GetSecurity(order.Symbol);
order.PriceCurrency = security.SymbolProperties.QuoteCurrency;
var orderEvent = new OrderEvent(order,
DateTime.UtcNow,
OrderFee.Zero)
{
Status = isUpdate ? OrderStatus.UpdateSubmitted : status,
FillPrice = Convert.ToDecimal(message.getPrice()),
FillQuantity = Convert.ToInt32(message.getSide() == SideFactory.BUY ? message.getLastQty() : -message.getLastQty()),
};
// we're catching the first fill so we apply the fees only once
if ((int)message.getCumQty() == (int)message.getLastQty() && message.getLastQty() > 0)
{
orderEvent.OrderFee = security.FeeModel.GetOrderFee(
new OrderFeeParameters(security, order));
}
_orderEventQueue.Enqueue(orderEvent);
}
}
else if (_mapRequestsToOrders.TryGetValue(message.getRequestID(), out order))
{
_mapFxcmOrderIdsToOrders[orderId] = order;
order.BrokerId.Add(orderId);
order.PriceCurrency = _securityProvider.GetSecurity(order.Symbol).SymbolProperties.QuoteCurrency;
// new order
var orderEvent = new OrderEvent(order,
DateTime.UtcNow,
OrderFee.Zero)
{
Status = ConvertOrderStatus(orderStatus)
};
_orderEventQueue.Enqueue(orderEvent);
}
}
if (message.getRequestID() == _currentRequest)
{
if (message.isLastRptRequested())
{
if (orderId == "NONE" && orderStatus.getCode() == IFixValueDefs.__Fields.FXCMORDSTATUS_REJECTED)
{
if (message.getSide() != SideFactory.UNDISCLOSED)
{
var messageText = message.getFXCMErrorDetails().Replace("\n", "");
Log.Trace("FxcmBrokerage.OnExecutionReport(): " + messageText);
OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Warning, "OrderSubmitReject", messageText));
}
_isOrderSubmitRejected = true;
}
AutoResetEvent autoResetEvent;
if (_mapRequestsToAutoResetEvents.TryGetValue(_currentRequest, out autoResetEvent))
{
autoResetEvent.Set();
_mapRequestsToAutoResetEvents.Remove(_currentRequest);
}
}
}
}
/// <summary>
/// RequestForPositionsAck message handler
/// </summary>
private void OnRequestForPositionsAck(RequestForPositionsAck message)
{
if (message.getRequestID() == _currentRequest)
{
if (message.getTotalNumPosReports() == 0)
{
_mapRequestsToAutoResetEvents[_currentRequest].Set();
_mapRequestsToAutoResetEvents.Remove(_currentRequest);
}
}
}
/// <summary>
/// PositionReport message handler
/// </summary>
private void OnPositionReport(PositionReport message)
{
if (message.getAccount() == _accountId)
{
var fxcmPositionId = message.getFXCMPosID();
if (_openPositions.ContainsKey(fxcmPositionId) && message is ClosedPositionReport)
{
_openPositions.Remove(fxcmPositionId);
}
else
{
_openPositions[fxcmPositionId] = message;
}
}
if (message.getRequestID() == _currentRequest)
{
AutoResetEvent autoResetEvent;
if (message.isLastRptRequested() && _mapRequestsToAutoResetEvents.TryGetValue(_currentRequest, out autoResetEvent))
{
autoResetEvent.Set();
_mapRequestsToAutoResetEvents.Remove(_currentRequest);
}
}
}
/// <summary>
/// OrderCancelReject message handler
/// </summary>
private void OnOrderCancelReject(OrderCancelReject message)
{
if (message.getRequestID() == _currentRequest)
{
var messageText = message.getFXCMErrorDetails().Replace("\n", "");
Log.Trace("FxcmBrokerage.OnOrderCancelReject(): " + messageText);
OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Warning, "OrderUpdateOrCancelReject", messageText));
_isOrderUpdateOrCancelRejected = true;
_mapRequestsToAutoResetEvents[_currentRequest].Set();
_mapRequestsToAutoResetEvents.Remove(_currentRequest);
}
}
#endregion
#region IStatusMessageListener implementation
/// <summary>
/// Receives status messages from the FXCM API
/// </summary>
/// <param name="message">Status message received</param>
public void messageArrived(ISessionStatus message)
{
switch (message.getStatusCode())
{
case ISessionStatus.__Fields.STATUSCODE_READY:
lock (_lockerConnectionMonitor)
{
_lastReadyMessageTime = DateTime.UtcNow;
}
break;
}
}
#endregion
}
}

View File

@@ -1,257 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using com.fxcm.entity;
using com.fxcm.fix;
using com.fxcm.fix.posttrade;
using com.fxcm.fix.trade;
using com.sun.rowset;
using java.util;
using NodaTime;
using QuantConnect.Orders;
namespace QuantConnect.Brokerages.Fxcm
{
/// <summary>
/// FXCM brokerage - private helper functions
/// </summary>
public partial class FxcmBrokerage
{
/// <summary>
/// Converts an FXCM order to a QuantConnect order.
/// </summary>
/// <param name="fxcmOrder">The FXCM order</param>
private Order ConvertOrder(ExecutionReport fxcmOrder)
{
Order order;
if (fxcmOrder.getOrdType() == OrdTypeFactory.LIMIT)
{
order = new LimitOrder
{
LimitPrice = Convert.ToDecimal(fxcmOrder.getPrice())
};
}
else if (fxcmOrder.getOrdType() == OrdTypeFactory.MARKET)
{
order = new MarketOrder();
}
else if (fxcmOrder.getOrdType() == OrdTypeFactory.STOP)
{
order = new StopMarketOrder
{
StopPrice = Convert.ToDecimal(fxcmOrder.getPrice())
};
}
else
{
throw new NotSupportedException("FxcmBrokerage.ConvertOrder(): The FXCM order type " + fxcmOrder.getOrdType() + " is not supported.");
}
var securityType = _symbolMapper.GetBrokerageSecurityType(fxcmOrder.getInstrument().getSymbol());
order.Symbol = _symbolMapper.GetLeanSymbol(fxcmOrder.getInstrument().getSymbol(), securityType, Market.FXCM);
order.Quantity = Convert.ToInt32(fxcmOrder.getOrderQty() * (fxcmOrder.getSide() == SideFactory.BUY ? +1 : -1));
order.Status = ConvertOrderStatus(fxcmOrder.getFXCMOrdStatus());
order.BrokerId.Add(fxcmOrder.getOrderID());
order.Properties.TimeInForce = ConvertTimeInForce(fxcmOrder.getTimeInForce());
order.Time = FromJavaDate(fxcmOrder.getTransactTime().toDate());
return order;
}
/// <summary>
/// Converts an FXCM order time in force to QuantConnect order time in force
/// </summary>
private static TimeInForce ConvertTimeInForce(ITimeInForce timeInForce)
{
if (timeInForce == TimeInForceFactory.GOOD_TILL_CANCEL)
return TimeInForce.GoodTilCanceled;
if (timeInForce == TimeInForceFactory.DAY)
return TimeInForce.Day;
throw new ArgumentOutOfRangeException();
}
/// <summary>
/// Converts an FXCM position to a QuantConnect holding.
/// </summary>
/// <param name="fxcmPosition">The FXCM position</param>
private Holding ConvertHolding(PositionReport fxcmPosition)
{
var securityType = _symbolMapper.GetBrokerageSecurityType(fxcmPosition.getInstrument().getSymbol());
return new Holding
{
Symbol = _symbolMapper.GetLeanSymbol(fxcmPosition.getInstrument().getSymbol(), securityType, Market.FXCM),
Type = securityType,
AveragePrice = Convert.ToDecimal(fxcmPosition.getSettlPrice()),
CurrencySymbol = "$",
Quantity = Convert.ToDecimal(fxcmPosition.getPositionQty().getLongQty() > 0
? fxcmPosition.getPositionQty().getLongQty()
: -fxcmPosition.getPositionQty().getShortQty())
};
}
/// <summary>
/// Converts an FXCM OrderStatus to a QuantConnect <see cref="OrderStatus"/>
/// </summary>
/// <param name="status"></param>
/// <returns></returns>
private static OrderStatus ConvertOrderStatus(ICode status)
{
var result = OrderStatus.None;
switch (status.getCode())
{
case IFixValueDefs.__Fields.FXCMORDSTATUS_INPROCESS:
case IFixValueDefs.__Fields.FXCMORDSTATUS_WAITING:
case IFixValueDefs.__Fields.FXCMORDSTATUS_EXECUTING:
result = OrderStatus.Submitted;
break;
case IFixValueDefs.__Fields.FXCMORDSTATUS_EXECUTED:
result = OrderStatus.Filled;
break;
case IFixValueDefs.__Fields.FXCMORDSTATUS_CANCELLED:
case IFixValueDefs.__Fields.FXCMORDSTATUS_EXPIRED:
result = OrderStatus.Canceled;
break;
case IFixValueDefs.__Fields.FXCMORDSTATUS_REJECTED:
result = OrderStatus.Invalid;
break;
}
return result;
}
/// <summary>
/// Returns true if the specified order is considered open, otherwise false
/// </summary>
private static bool OrderIsOpen(string orderStatus)
{
return orderStatus == IFixValueDefs.__Fields.FXCMORDSTATUS_WAITING;
}
/// <summary>
/// Returns true if the specified order is considered close, otherwise false
/// </summary>
protected static bool OrderIsClosed(string orderStatus)
{
return orderStatus == IFixValueDefs.__Fields.FXCMORDSTATUS_EXECUTED
|| orderStatus == IFixValueDefs.__Fields.FXCMORDSTATUS_CANCELLED
|| orderStatus == IFixValueDefs.__Fields.FXCMORDSTATUS_EXPIRED
|| orderStatus == IFixValueDefs.__Fields.FXCMORDSTATUS_REJECTED;
}
/// <summary>
/// Returns true if the specified order is being processed, otherwise false
/// </summary>
private static bool OrderIsBeingProcessed(string orderStatus)
{
return !OrderIsOpen(orderStatus) && !OrderIsClosed(orderStatus);
}
/// <summary>
/// Converts a Java Date value to a UTC DateTime value
/// </summary>
/// <param name="javaDate">The Java date</param>
/// <returns></returns>
private static DateTime FromJavaDate(Date javaDate)
{
// Convert javaDate to UTC Instant (Epoch)
var instant = Instant.FromUnixTimeMilliseconds(javaDate.getTime());
// Convert to .Net UTC DateTime
return instant.ToDateTimeUtc();
}
/// <summary>
/// Converts a LEAN Resolution to an IFXCMTimingInterval
/// </summary>
/// <param name="resolution">The resolution to convert</param>
/// <returns></returns>
public static IFXCMTimingInterval ToFxcmInterval(Resolution resolution)
{
IFXCMTimingInterval interval = null;
switch (resolution)
{
case Resolution.Tick:
interval = FXCMTimingIntervalFactory.TICK;
break;
case Resolution.Second:
interval = FXCMTimingIntervalFactory.SEC10;
break;
case Resolution.Minute:
interval = FXCMTimingIntervalFactory.MIN1;
break;
case Resolution.Hour:
interval = FXCMTimingIntervalFactory.HOUR1;
break;
case Resolution.Daily:
interval = FXCMTimingIntervalFactory.DAY1;
break;
}
return interval;
}
/// <summary>
/// Converts a Java Date value to a UTC DateTime value
/// </summary>
/// <param name="utcDateTime">The UTC DateTime value</param>
/// <returns>A UTC Java Date value</returns>
public static Date ToJavaDateUtc(DateTime utcDateTime)
{
var cal = Calendar.getInstance();
cal.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
cal.set(Calendar.YEAR, utcDateTime.Year);
cal.set(Calendar.MONTH, utcDateTime.Month - 1);
cal.set(Calendar.DAY_OF_MONTH, utcDateTime.Day);
cal.set(Calendar.HOUR_OF_DAY, utcDateTime.Hour);
cal.set(Calendar.MINUTE, utcDateTime.Minute);
cal.set(Calendar.SECOND, utcDateTime.Second);
cal.set(Calendar.MILLISECOND, utcDateTime.Millisecond);
return cal.getTime();
}
//
// So it turns out that in order to properly load the QuantConnect.Brokerages
// dll we need the IKVM.OpenJdk.Jdbc referenced in other projects that use
// this. By placing a hard reference to an IKVM.OpenJdk.Jdbc type, the compiler
// will properly copy the required dlls into other project bin directories.
// Without this, consuming projects would need to hard refernce the IKVM dlls,
// which is less than perfect. This seems to be the better of two evils
//
private static void ManageIKVMDependency()
{
var rowset = new CachedRowSetImpl();
}
}
}

View File

@@ -1,781 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
using com.fxcm.external.api.transport;
using com.fxcm.external.api.transport.listeners;
using com.fxcm.external.api.util;
using com.fxcm.fix;
using com.fxcm.fix.pretrade;
using com.fxcm.fix.trade;
using com.fxcm.messaging.util;
using NodaTime;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using QuantConnect.Logging;
using QuantConnect.Orders;
using QuantConnect.Securities;
namespace QuantConnect.Brokerages.Fxcm
{
/// <summary>
/// FXCM brokerage - implementation of IBrokerage interface
/// </summary>
[BrokerageFactory(typeof(FxcmBrokerageFactory))]
public partial class FxcmBrokerage : Brokerage, IDataQueueHandler, IGenericMessageListener, IStatusMessageListener
{
private readonly IOrderProvider _orderProvider;
private readonly ISecurityProvider _securityProvider;
private readonly IDataAggregator _aggregator;
private readonly string _server;
private readonly string _terminal;
private readonly string _userName;
private readonly string _password;
private readonly string _accountId;
private Thread _orderEventThread;
private Thread _connectionMonitorThread;
private readonly object _lockerConnectionMonitor = new object();
private DateTime _lastReadyMessageTime;
private volatile bool _connectionLost;
// tracks requested order updates, so we can flag Submitted order events as updates
private readonly ConcurrentDictionary<int, int> _orderUpdates = new ConcurrentDictionary<int, int>();
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private readonly ConcurrentQueue<OrderEvent> _orderEventQueue = new ConcurrentQueue<OrderEvent>();
private readonly FxcmSymbolMapper _symbolMapper = new FxcmSymbolMapper();
private readonly EventBasedDataQueueHandlerSubscriptionManager _subscriptionManager;
private readonly IList<BaseData> _lastHistoryChunk = new List<BaseData>();
private readonly Dictionary<Symbol, DateTimeZone> _symbolExchangeTimeZones = new Dictionary<Symbol, DateTimeZone>();
/// <summary>
/// Gets/sets a timeout for history requests (in milliseconds)
/// </summary>
public int HistoryResponseTimeout { get; set; }
/// <summary>
/// Gets/sets the maximum number of retries for a history request
/// </summary>
public int MaximumHistoryRetryAttempts { get; set; }
/// <summary>
/// Gets/sets a value to enable only history requests to this brokerage
/// Set to true in parallel downloaders to avoid loading accounts, orders, positions etc. at connect time
/// </summary>
public bool EnableOnlyHistoryRequests { get; set; }
/// <summary>
/// Static constructor for the <see cref="FxcmBrokerage"/> class
/// </summary>
static FxcmBrokerage()
{
// FXCM requires TLS 1.2 since 6/16/2019
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
}
/// <summary>
/// Creates a new instance of the <see cref="FxcmBrokerage"/> class
/// </summary>
/// <param name="orderProvider">The order provider</param>
/// <param name="securityProvider">The holdings provider</param>
/// <param name="aggregator">Consolidate ticks</param>
/// <param name="server">The url of the server</param>
/// <param name="terminal">The terminal name</param>
/// <param name="userName">The user name (login id)</param>
/// <param name="password">The user password</param>
/// <param name="accountId">The account id</param>
public FxcmBrokerage(IOrderProvider orderProvider, ISecurityProvider securityProvider, IDataAggregator aggregator, string server, string terminal, string userName, string password, string accountId)
: base("FXCM Brokerage")
{
_orderProvider = orderProvider;
_securityProvider = securityProvider;
_aggregator = aggregator;
_server = server;
_terminal = terminal;
_userName = userName;
_password = password;
_accountId = accountId;
_subscriptionManager = new EventBasedDataQueueHandlerSubscriptionManager();
_subscriptionManager.SubscribeImpl += (s, t) => Subscribe(s);
_subscriptionManager.UnsubscribeImpl += (s, t) => Unsubscribe(s);
HistoryResponseTimeout = 5000;
MaximumHistoryRetryAttempts = 1;
}
#region IBrokerage implementation
/// <summary>
/// Returns true if we're currently connected to the broker
/// </summary>
public override bool IsConnected
{
get
{
return _gateway != null && _gateway.isConnected() && !_connectionLost;
}
}
/// <summary>
/// Connects the client to the broker's remote servers
/// </summary>
public override void Connect()
{
if (IsConnected) return;
Log.Trace("FxcmBrokerage.Connect()");
_cancellationTokenSource = new CancellationTokenSource();
// create new thread to fire order events in queue
if (!EnableOnlyHistoryRequests)
{
_orderEventThread = new Thread(() =>
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
try
{
OrderEvent orderEvent;
if (!_orderEventQueue.TryDequeue(out orderEvent))
{
Thread.Sleep(1);
continue;
}
OnOrderEvent(orderEvent);
}
catch (Exception exception)
{
Log.Error(exception);
}
}
}) { IsBackground = true };
_orderEventThread.Start();
while (!_orderEventThread.IsAlive)
{
Thread.Sleep(1);
}
}
// create the gateway
_gateway = GatewayFactory.createGateway();
// register the message listeners with the gateway
_gateway.registerGenericMessageListener(this);
_gateway.registerStatusMessageListener(this);
// create local login properties
var loginProperties = new FXCMLoginProperties(_userName, _password, _terminal, _server);
loginProperties.addProperty(IConnectionManager.APP_INFO, "QuantConnect");
// log in
try
{
_gateway.login(loginProperties);
}
catch (Exception err)
{
var message =
err.Message.Contains("ORA-20101") ? "Incorrect login credentials" :
err.Message.Contains("ORA-20003") ? "Contact api@fxcm.com to enable API access, below is a template email. " + Environment.NewLine +
"Email: api@fxcm.com " + Environment.NewLine +
"Template: " + Environment.NewLine +
"Hello FXCM staff, " + Environment.NewLine +
"Please enable Java API for all accounts which are associated with this email address. " + Environment.NewLine +
"Also, please respond to this email address once Java API has been enabled, letting me know that the change was done successfully." :
err.Message;
_cancellationTokenSource.Cancel();
throw new BrokerageException(message, err.InnerException);
}
// create new thread to manage disconnections and reconnections
if (!EnableOnlyHistoryRequests)
{
_connectionMonitorThread = new Thread(() =>
{
_lastReadyMessageTime = DateTime.UtcNow;
try
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
TimeSpan elapsed;
lock (_lockerConnectionMonitor)
{
elapsed = DateTime.UtcNow - _lastReadyMessageTime;
}
if (!_connectionLost && elapsed > TimeSpan.FromSeconds(10))
{
_connectionLost = true;
OnMessage(BrokerageMessageEvent.Disconnected("Connection with FXCM server lost. " +
"This could be because of internet connectivity issues. "));
}
else if (_connectionLost && IsWithinTradingHours())
{
Log.Trace("FxcmBrokerage.ConnectionMonitorThread(): Attempting reconnection...");
try
{
// log out
try
{
_gateway.logout();
}
catch (Exception)
{
// ignored
}
// remove the message listeners
_gateway.removeGenericMessageListener(this);
_gateway.removeStatusMessageListener(this);
// register the message listeners with the gateway
_gateway.registerGenericMessageListener(this);
_gateway.registerStatusMessageListener(this);
// log in
_gateway.login(loginProperties);
// load instruments, accounts, orders, positions
LoadInstruments();
if (!EnableOnlyHistoryRequests)
{
LoadAccounts();
LoadOpenOrders();
LoadOpenPositions();
}
_connectionLost = false;
OnMessage(BrokerageMessageEvent.Reconnected("Connection with FXCM server restored."));
}
catch (Exception exception)
{
Log.Trace("FxcmBrokerage.ConnectionMonitorThread(): reconnect failed.");
Log.Error(exception);
}
}
Thread.Sleep(5000);
}
}
catch (Exception exception)
{
Log.Error(exception);
}
}) { IsBackground = true };
_connectionMonitorThread.Start();
while (!_connectionMonitorThread.IsAlive)
{
Thread.Sleep(1);
}
}
// load instruments, accounts, orders, positions
LoadInstruments();
if (!EnableOnlyHistoryRequests)
{
LoadAccounts();
LoadOpenOrders();
LoadOpenPositions();
}
}
/// <summary>
/// Returns true if we are within FXCM trading hours
/// </summary>
/// <returns></returns>
private static bool IsWithinTradingHours()
{
var time = DateTime.UtcNow.ConvertFromUtc(TimeZones.EasternStandard);
// FXCM Trading Hours: http://help.fxcm.com/us/Trading-Basics/New-to-Forex/38757093/What-are-the-Trading-Hours.htm
return !(time.DayOfWeek == DayOfWeek.Friday && time.TimeOfDay > new TimeSpan(16, 55, 0) ||
time.DayOfWeek == DayOfWeek.Saturday ||
time.DayOfWeek == DayOfWeek.Sunday && time.TimeOfDay < new TimeSpan(17, 0, 0) ||
time.Month == 12 && time.Day == 25 ||
time.Month == 1 && time.Day == 1);
}
/// <summary>
/// Disconnects the client from the broker's remote servers
/// </summary>
public override void Disconnect()
{
Log.Trace("FxcmBrokerage.Disconnect()");
if (_gateway != null)
{
// log out
try
{
if (_gateway.isConnected())
_gateway.logout();
}
catch (Exception)
{
// ignored
}
// remove the message listeners
_gateway.removeGenericMessageListener(this);
_gateway.removeStatusMessageListener(this);
}
// request and wait for thread to stop
if (_cancellationTokenSource != null) _cancellationTokenSource.Cancel();
if (!EnableOnlyHistoryRequests)
{
if (_orderEventThread != null) _orderEventThread.Join();
if (_connectionMonitorThread != null) _connectionMonitorThread.Join();
}
}
/// <summary>
/// Gets all open orders on the account.
/// NOTE: The order objects returned do not have QC order IDs.
/// </summary>
/// <returns>The open orders returned from FXCM</returns>
public override List<Order> GetOpenOrders()
{
Log.Trace($"FxcmBrokerage.GetOpenOrders(): Located {_openOrders.Count.ToStringInvariant()} orders");
var orders = _openOrders.Values.ToList()
.Where(x => OrderIsOpen(x.getFXCMOrdStatus().getCode()))
.Select(ConvertOrder)
.ToList();
return orders;
}
/// <summary>
/// Gets all holdings for the account
/// </summary>
/// <returns>The current holdings from the account</returns>
public override List<Holding> GetAccountHoldings()
{
Log.Trace("FxcmBrokerage.GetAccountHoldings()");
// FXCM maintains multiple positions per symbol, so we aggregate them by symbol.
// The average price for the aggregated position is the quantity weighted average price.
var holdings = _openPositions.Values
.Select(ConvertHolding)
.Where(x => x.Quantity != 0)
.GroupBy(x => x.Symbol)
.Select(group => new Holding
{
Symbol = group.Key,
Type = group.First().Type,
AveragePrice = group.Sum(x => x.AveragePrice * x.Quantity) / group.Sum(x => x.Quantity),
CurrencySymbol = group.First().CurrencySymbol,
Quantity = group.Sum(x => x.Quantity)
})
.ToList();
// Set MarketPrice in each Holding
var fxcmSymbols = holdings
.Select(x => _symbolMapper.GetBrokerageSymbol(x.Symbol))
.ToList();
if (fxcmSymbols.Count > 0)
{
var quotes = GetQuotes(fxcmSymbols).ToDictionary(x => x.getInstrument().getSymbol());
foreach (var holding in holdings)
{
MarketDataSnapshot quote;
if (quotes.TryGetValue(_symbolMapper.GetBrokerageSymbol(holding.Symbol), out quote))
{
holding.MarketPrice = Convert.ToDecimal((quote.getBidClose() + quote.getAskClose()) / 2);
}
}
}
return holdings;
}
/// <summary>
/// Gets the current cash balance for each currency held in the brokerage account
/// </summary>
/// <returns>The current cash balance for each currency available for trading</returns>
public override List<CashAmount> GetCashBalance()
{
Log.Trace("FxcmBrokerage.GetCashBalance()");
var cashBook = new List<CashAmount>();
//Adds the account currency to the cashbook.
cashBook.Add(new CashAmount(Convert.ToDecimal(_accounts[_accountId].getCashOutstanding()),
AccountBaseCurrency));
// include cash balances from currency swaps for open Forex positions
foreach (var trade in _openPositions.Values)
{
var brokerageSymbol = trade.getInstrument().getSymbol();
var ticker = FxcmSymbolMapper.ConvertFxcmSymbolToLeanSymbol(brokerageSymbol);
var securityType = _symbolMapper.GetBrokerageSecurityType(brokerageSymbol);
if (securityType == SecurityType.Forex)
{
//settlement price for the trade
var settlementPrice = Convert.ToDecimal(trade.getSettlPrice());
//direction of trade
var direction = trade.getPositionQty().getLongQty() > 0 ? 1 : -1;
//quantity of the asset
var quantity = Convert.ToDecimal(trade.getPositionQty().getQty());
//quantity of base currency
var baseQuantity = direction * quantity;
//quantity of quote currency
var quoteQuantity = -direction * quantity * settlementPrice;
//base currency
var baseCurrency = trade.getCurrency();
//quote currency
var quoteCurrency = ticker.Substring(ticker.Length - 3);
var baseCurrencyAmount = cashBook.FirstOrDefault(x => x.Currency == baseCurrency);
//update the value of the base currency
if (baseCurrencyAmount != default(CashAmount))
{
cashBook.Remove(baseCurrencyAmount);
cashBook.Add(new CashAmount(baseQuantity + baseCurrencyAmount.Amount, baseCurrency));
}
else
{
//add the base currency if not present
cashBook.Add(new CashAmount(baseQuantity, baseCurrency));
}
var quoteCurrencyAmount = cashBook.Find(x => x.Currency == quoteCurrency);
//update the value of the quote currency
if (quoteCurrencyAmount != default(CashAmount))
{
cashBook.Remove(quoteCurrencyAmount);
cashBook.Add(new CashAmount(quoteQuantity + quoteCurrencyAmount.Amount, quoteCurrency));
}
else
{
//add the quote currency if not present
cashBook.Add(new CashAmount(quoteQuantity, quoteCurrency));
}
}
}
return cashBook;
}
/// <summary>
/// Places a new order and assigns a new broker ID to the order
/// </summary>
/// <param name="order">The order to be placed</param>
/// <returns>True if the request for a new order has been placed, false otherwise</returns>
public override bool PlaceOrder(Order order)
{
Log.Trace("FxcmBrokerage.PlaceOrder(): {0}", order);
if (!IsConnected)
throw new InvalidOperationException("FxcmBrokerage.PlaceOrder(): Unable to place order while not connected.");
if (order.Direction != OrderDirection.Buy && order.Direction != OrderDirection.Sell)
throw new ArgumentException("FxcmBrokerage.PlaceOrder(): Invalid Order Direction");
var fxcmSymbol = _symbolMapper.GetBrokerageSymbol(order.Symbol);
var orderSide = order.Direction == OrderDirection.Buy ? SideFactory.BUY : SideFactory.SELL;
var quantity = (double)order.AbsoluteQuantity;
OrderSingle orderRequest;
switch (order.Type)
{
case OrderType.Market:
orderRequest = MessageGenerator.generateMarketOrder(_accountId, quantity, orderSide, fxcmSymbol, "");
break;
case OrderType.Limit:
var limitPrice = (double)((LimitOrder)order).LimitPrice;
orderRequest = MessageGenerator.generateOpenOrder(limitPrice, _accountId, quantity, orderSide, fxcmSymbol, "");
orderRequest.setOrdType(OrdTypeFactory.LIMIT);
orderRequest.setTimeInForce(TimeInForceFactory.GOOD_TILL_CANCEL);
break;
case OrderType.StopMarket:
var stopPrice = (double)((StopMarketOrder)order).StopPrice;
orderRequest = MessageGenerator.generateOpenOrder(stopPrice, _accountId, quantity, orderSide, fxcmSymbol, "");
orderRequest.setOrdType(OrdTypeFactory.STOP);
orderRequest.setTimeInForce(TimeInForceFactory.GOOD_TILL_CANCEL);
break;
default:
throw new NotSupportedException("FxcmBrokerage.PlaceOrder(): Order type " + order.Type + " is not supported.");
}
_isOrderSubmitRejected = false;
AutoResetEvent autoResetEvent;
lock (_locker)
{
_currentRequest = _gateway.sendMessage(orderRequest);
_mapRequestsToOrders[_currentRequest] = order;
autoResetEvent = new AutoResetEvent(false);
_mapRequestsToAutoResetEvents[_currentRequest] = autoResetEvent;
}
if (!autoResetEvent.WaitOne(ResponseTimeout))
throw new TimeoutException("FxcmBrokerage.PlaceOrder(): Operation took longer than " +
$"{((decimal) ResponseTimeout / 1000).ToStringInvariant()} seconds."
);
return !_isOrderSubmitRejected;
}
/// <summary>
/// Updates the order with the same id
/// </summary>
/// <param name="order">The new order information</param>
/// <returns>True if the request was made for the order to be updated, false otherwise</returns>
public override bool UpdateOrder(Order order)
{
Log.Trace("FxcmBrokerage.UpdateOrder(): {0}", order);
if (!IsConnected)
throw new InvalidOperationException("FxcmBrokerage.UpdateOrder(): Unable to update order while not connected.");
if (!order.BrokerId.Any())
{
// we need the brokerage order id in order to perform an update
Log.Trace("FxcmBrokerage.UpdateOrder(): Unable to update order without BrokerId.");
return false;
}
var fxcmOrderId = order.BrokerId[0].ToStringInvariant();
ExecutionReport fxcmOrder;
if (!_openOrders.TryGetValue(fxcmOrderId, out fxcmOrder))
throw new ArgumentException("FxcmBrokerage.UpdateOrder(): FXCM order id not found: " + fxcmOrderId);
double price;
switch (order.Type)
{
case OrderType.Limit:
price = (double)((LimitOrder)order).LimitPrice;
break;
case OrderType.StopMarket:
price = (double)((StopMarketOrder)order).StopPrice;
break;
default:
throw new NotSupportedException("FxcmBrokerage.UpdateOrder(): Invalid order type.");
}
_isOrderUpdateOrCancelRejected = false;
var orderReplaceRequest = MessageGenerator.generateOrderReplaceRequest("", fxcmOrder.getOrderID(), fxcmOrder.getSide(), fxcmOrder.getOrdType(), price, fxcmOrder.getAccount());
orderReplaceRequest.setInstrument(fxcmOrder.getInstrument());
orderReplaceRequest.setOrderQty((double)order.AbsoluteQuantity);
AutoResetEvent autoResetEvent;
lock (_locker)
{
_orderUpdates[order.Id] = order.Id;
_currentRequest = _gateway.sendMessage(orderReplaceRequest);
autoResetEvent = new AutoResetEvent(false);
_mapRequestsToAutoResetEvents[_currentRequest] = autoResetEvent;
}
if (!autoResetEvent.WaitOne(ResponseTimeout))
throw new TimeoutException("FxcmBrokerage.UpdateOrder(): Operation took longer than " +
$"{((decimal) ResponseTimeout / 1000).ToStringInvariant()} seconds."
);
return !_isOrderUpdateOrCancelRejected;
}
/// <summary>
/// Cancels the order with the specified ID
/// </summary>
/// <param name="order">The order to cancel</param>
/// <returns>True if the request was made for the order to be canceled, false otherwise</returns>
public override bool CancelOrder(Order order)
{
Log.Trace("FxcmBrokerage.CancelOrder(): {0}", order);
if (!IsConnected)
throw new InvalidOperationException("FxcmBrokerage.UpdateOrder(): Unable to cancel order while not connected.");
if (!order.BrokerId.Any())
{
// we need the brokerage order id in order to perform a cancellation
Log.Trace("FxcmBrokerage.CancelOrder(): Unable to cancel order without BrokerId.");
return false;
}
var fxcmOrderId = order.BrokerId[0].ToStringInvariant();
ExecutionReport fxcmOrder;
if (!_openOrders.TryGetValue(fxcmOrderId, out fxcmOrder))
throw new ArgumentException("FxcmBrokerage.CancelOrder(): FXCM order id not found: " + fxcmOrderId);
_isOrderUpdateOrCancelRejected = false;
var orderCancelRequest = MessageGenerator.generateOrderCancelRequest("", fxcmOrder.getOrderID(), fxcmOrder.getSide(), fxcmOrder.getAccount());
AutoResetEvent autoResetEvent;
lock (_locker)
{
_currentRequest = _gateway.sendMessage(orderCancelRequest);
autoResetEvent = new AutoResetEvent(false);
_mapRequestsToAutoResetEvents[_currentRequest] = autoResetEvent;
}
if (!autoResetEvent.WaitOne(ResponseTimeout))
throw new TimeoutException("FxcmBrokerage.CancelOrder(): Operation took longer than " +
$"{((decimal) ResponseTimeout / 1000).ToStringInvariant()} seconds."
);
return !_isOrderUpdateOrCancelRejected;
}
/// <summary>
/// Gets the history for the requested security
/// </summary>
/// <param name="request">The historical data request</param>
/// <returns>An enumerable of bars covering the span specified in the request</returns>
public override IEnumerable<BaseData> GetHistory(HistoryRequest request)
{
if (!_symbolMapper.IsKnownLeanSymbol(request.Symbol))
{
Log.Trace("FxcmBrokerage.GetHistory(): Invalid symbol: {0}, no history returned", request.Symbol.Value);
yield break;
}
// cache exchange time zone for symbol
DateTimeZone exchangeTimeZone;
if (!_symbolExchangeTimeZones.TryGetValue(request.Symbol, out exchangeTimeZone))
{
exchangeTimeZone = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.FXCM, request.Symbol, request.Symbol.SecurityType).TimeZone;
_symbolExchangeTimeZones.Add(request.Symbol, exchangeTimeZone);
}
var interval = ToFxcmInterval(request.Resolution);
// download data
var history = new List<BaseData>();
var lastEndTime = DateTime.MinValue;
var end = request.EndTimeUtc;
var attempt = 1;
while (end > request.StartTimeUtc)
{
Log.Debug($"FxcmBrokerage.GetHistory(): Requesting {end.ToIso8601Invariant()} to {request.StartTimeUtc.ToIso8601Invariant()}");
_lastHistoryChunk.Clear();
var mdr = new MarketDataRequest();
mdr.setSubscriptionRequestType(SubscriptionRequestTypeFactory.SNAPSHOT);
mdr.setResponseFormat(IFixMsgTypeDefs.__Fields.MSGTYPE_FXCMRESPONSE);
mdr.setFXCMTimingInterval(interval);
mdr.setMDEntryTypeSet(MarketDataRequest.MDENTRYTYPESET_ALL);
mdr.setFXCMStartDate(new UTCDate(ToJavaDateUtc(request.StartTimeUtc)));
mdr.setFXCMStartTime(new UTCTimeOnly(ToJavaDateUtc(request.StartTimeUtc)));
mdr.setFXCMEndDate(new UTCDate(ToJavaDateUtc(end)));
mdr.setFXCMEndTime(new UTCTimeOnly(ToJavaDateUtc(end)));
mdr.addRelatedSymbol(_fxcmInstruments[_symbolMapper.GetBrokerageSymbol(request.Symbol)]);
AutoResetEvent autoResetEvent;
lock (_locker)
{
_currentRequest = _gateway.sendMessage(mdr);
autoResetEvent = new AutoResetEvent(false);
_mapRequestsToAutoResetEvents[_currentRequest] = autoResetEvent;
_pendingHistoryRequests.Add(_currentRequest);
}
if (!autoResetEvent.WaitOne(HistoryResponseTimeout))
{
// No response can mean genuine timeout or the history data has ended.
// 90% of the time no response because no data; widen the search net to 5m if we don't get a response:
if (request.StartTimeUtc.AddSeconds(300) >= end)
{
break;
}
// 5% of the time its because the data ends at a specific, repeatible time not close to our desired endtime:
if (end == lastEndTime)
{
Log.Trace("FxcmBrokerage.GetHistory(): Request for {0} ended at {1:O}", request.Symbol.Value, end);
break;
}
// 5% of the time its because of an internet / time of day / api settings / timeout: throw if this is the *second* attempt.
if (EnableOnlyHistoryRequests && lastEndTime != DateTime.MinValue)
{
throw new TimeoutException("FxcmBrokerage.GetHistory(): History operation ending in {end:O} took longer than " +
$"{((decimal) HistoryResponseTimeout / 1000).ToStringInvariant()} seconds. This may be because there is no data, retrying..."
);
}
// Assuming Timeout: If we've already retried quite a few times, lets bail.
if (++attempt > MaximumHistoryRetryAttempts)
{
Log.Trace("FxcmBrokerage.GetHistory(): Maximum attempts reached for: " + request.Symbol.Value);
break;
}
// Assuming Timeout: Save end time and if have the same endtime next time, break since its likely there's no data after that time.
lastEndTime = end;
Log.Trace($"FxcmBrokerage.GetHistory(): Attempt {attempt.ToStringInvariant()} for: " +
$"{request.Symbol.Value} ended at {lastEndTime.ToIso8601Invariant()}"
);
continue;
}
// Add data
lock (_locker)
{
history.InsertRange(0, _lastHistoryChunk);
}
var firstDateUtc = _lastHistoryChunk[0].Time.ConvertToUtc(exchangeTimeZone);
if (end != firstDateUtc)
{
// new end date = first datapoint date.
end = request.Resolution == Resolution.Tick ? firstDateUtc.AddMilliseconds(-1) : firstDateUtc.AddSeconds(-1);
if (request.StartTimeUtc.AddSeconds(10) >= end)
break;
}
else
{
break;
}
}
foreach (var data in history)
{
yield return data;
}
}
#endregion
}
}

View File

@@ -1,125 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Configuration;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using QuantConnect.Packets;
using QuantConnect.Securities;
using QuantConnect.Util;
namespace QuantConnect.Brokerages.Fxcm
{
/// <summary>
/// Provides an implementation of <see cref="IBrokerageFactory"/> that produces a <see cref="FxcmBrokerage"/>
/// </summary>
public class FxcmBrokerageFactory : BrokerageFactory
{
private const string DefaultServer = "http://www.fxcorporate.com/Hosts.jsp";
private const string DefaultTerminal = "Demo";
/// <summary>
/// Initializes a new instance of the <see cref="FxcmBrokerageFactory"/> class
/// </summary>
public FxcmBrokerageFactory()
: base(typeof(FxcmBrokerage))
{
}
/// <summary>
/// Gets the brokerage data required to run the brokerage from configuration/disk
/// </summary>
/// <remarks>
/// The implementation of this property will create the brokerage data dictionary required for
/// running live jobs. See <see cref="IJobQueueHandler.NextJob"/>
/// </remarks>
public override Dictionary<string, string> BrokerageData
{
get
{
return new Dictionary<string, string>
{
{ "fxcm-server", Config.Get("fxcm-server", DefaultServer) },
{ "fxcm-terminal", Config.Get("fxcm-terminal", DefaultTerminal) },
{ "fxcm-user-name", Config.Get("fxcm-user-name") },
{ "fxcm-password", Config.Get("fxcm-password") },
{ "fxcm-account-id", Config.Get("fxcm-account-id") }
};
}
}
/// <summary>
/// Gets a new instance of the <see cref="FxcmBrokerageModel"/>
/// </summary>
/// <param name="orderProvider">The order provider</param>
public override IBrokerageModel GetBrokerageModel(IOrderProvider orderProvider) => new FxcmBrokerageModel();
/// <summary>
/// Creates a new <see cref="IBrokerage"/> instance
/// </summary>
/// <param name="job">The job packet to create the brokerage for</param>
/// <param name="algorithm">The algorithm instance</param>
/// <returns>A new brokerage instance</returns>
public override IBrokerage CreateBrokerage(LiveNodePacket job, IAlgorithm algorithm)
{
var errors = new List<string>();
// read values from the brokerage data
var server = Read<string>(job.BrokerageData, "fxcm-server", errors);
var terminal = Read<string>(job.BrokerageData, "fxcm-terminal", errors);
var userName = Read<string>(job.BrokerageData, "fxcm-user-name", errors);
var password = Read<string>(job.BrokerageData, "fxcm-password", errors);
var accountId = Read<string>(job.BrokerageData, "fxcm-account-id", errors);
if (errors.Count != 0)
{
// if we had errors then we can't create the instance
throw new Exception(string.Join(Environment.NewLine, errors));
}
var brokerage = new FxcmBrokerage(
algorithm.Transactions,
algorithm.Portfolio,
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager")),
server,
terminal,
userName,
password,
accountId);
Composer.Instance.AddPart<IDataQueueHandler>(brokerage);
return brokerage;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public override void Dispose()
{
}
/// <summary>
/// Gets a brokerage message handler
/// </summary>
public override IBrokerageMessageHandler CreateBrokerageMessageHandler(IAlgorithm algorithm, AlgorithmNodePacket job, IApi api)
{
//We have chosen a timespan of negative 30 beacause FXCM market hours don't always open on time.
return new DefaultBrokerageMessageHandler(algorithm, job, api, openThreshold: TimeSpan.FromMinutes(-30));
}
}
}

View File

@@ -1,267 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
namespace QuantConnect.Brokerages.Fxcm
{
/// <summary>
/// Provides the mapping between Lean symbols and FXCM symbols.
/// </summary>
public class FxcmSymbolMapper : ISymbolMapper
{
/// <summary>
/// List of all known symbols for FXCM
/// </summary>
public static List<Symbol> KnownSymbols
{
get
{
var symbols = new List<Symbol>();
var mapper = new FxcmSymbolMapper();
foreach (var tp in FxcmSymbolMappings)
{
symbols.Add(mapper.GetLeanSymbol(tp.Item1, mapper.GetBrokerageSecurityType(tp.Item1), Market.FXCM));
}
return symbols;
}
}
/// <summary>
/// Helper class to allow collection initializer on a List of tuples
/// </summary>
private class TupleList<T1, T2> : List<Tuple<T1, T2>>
{
public void Add(T1 item1, T2 item2)
{
Add(new Tuple<T1, T2>(item1, item2));
}
}
/// <summary>
/// The list of mappings from FXCM symbols to Lean symbols.
/// </summary>
/// <remarks>T1 is FXCM symbol, T2 is Lean symbol</remarks>
private static readonly TupleList<string, string> FxcmSymbolMappings = new TupleList<string, string>
{
{ "AUD/CAD", "AUDCAD" },
{ "AUD/CHF", "AUDCHF" },
{ "AUD/JPY", "AUDJPY" },
{ "AUD/NZD", "AUDNZD" },
{ "AUD/USD", "AUDUSD" },
{ "AUS200", "AU200AUD" },
{ "Bund", "DE10YBEUR" },
{ "CAD/CHF", "CADCHF" },
{ "CAD/JPY", "CADJPY" },
{ "CHF/JPY", "CHFJPY" },
{ "Copper", "XCUUSD" },
{ "ESP35", "ES35EUR" },
{ "EUR/AUD", "EURAUD" },
{ "EUR/CAD", "EURCAD" },
{ "EUR/CHF", "EURCHF" },
{ "EUR/GBP", "EURGBP" },
{ "EUR/JPY", "EURJPY" },
{ "EUR/NOK", "EURNOK" },
{ "EUR/NZD", "EURNZD" },
{ "EUR/SEK", "EURSEK" },
{ "EUR/TRY", "EURTRY" },
{ "EUR/USD", "EURUSD" },
{ "EUSTX50", "EU50EUR" },
{ "FRA40", "FR40EUR" },
{ "GBP/AUD", "GBPAUD" },
{ "GBP/CAD", "GBPCAD" },
{ "GBP/CHF", "GBPCHF" },
{ "GBP/JPY", "GBPJPY" },
{ "GBP/NZD", "GBPNZD" },
{ "GBP/USD", "GBPUSD" },
{ "GER30", "DE30EUR" },
{ "HKG33", "HK33HKD" },
{ "ITA40", "IT40EUR" },
{ "JPN225", "JP225JPY" },
{ "NAS100", "NAS100USD" },
{ "NGAS", "NATGASUSD" },
{ "NZD/CAD", "NZDCAD" },
{ "NZD/CHF", "NZDCHF" },
{ "NZD/JPY", "NZDJPY" },
{ "NZD/USD", "NZDUSD" },
{ "SPX500", "SPX500USD" },
{ "SUI20", "CH20CHF" },
{ "TRY/JPY", "TRYJPY" },
{ "UK100", "UK100GBP" },
{ "UKOil", "BCOUSD" },
{ "US30", "US30USD" },
{ "USD/MXN", "USDMXN" },
{ "USDOLLAR", "DXYUSD" },
{ "USD/CAD", "USDCAD" },
{ "USD/CHF", "USDCHF" },
{ "USD/CNH", "USDCNH" },
{ "USD/HKD", "USDHKD" },
{ "USD/JPY", "USDJPY" },
{ "USD/NOK", "USDNOK" },
{ "USD/SEK", "USDSEK" },
{ "USD/TRY", "USDTRY" },
{ "USD/ZAR", "USDZAR" },
{ "USOil", "WTICOUSD" },
{ "XAG/USD", "XAGUSD" },
{ "XAU/USD", "XAUUSD" },
{ "XPD/USD", "XPDUSD" },
{ "XPT/USD", "XPTUSD" },
{ "ZAR/JPY", "ZARJPY" }
};
private static readonly Dictionary<string, string> MapFxcmToLean = new Dictionary<string, string>();
private static readonly Dictionary<string, string> MapLeanToFxcm = new Dictionary<string, string>();
/// <summary>
/// The list of known FXCM currencies.
/// </summary>
private static readonly HashSet<string> KnownCurrencies = new HashSet<string>
{
"AUD", "CAD", "CHF", "CNH", "EUR", "GBP", "HKD", "JPY", "MXN", "NOK", "NZD", "SEK", "TRY", "USD", "ZAR"
};
/// <summary>
/// Static constructor for the <see cref="FxcmSymbolMapper"/> class
/// </summary>
static FxcmSymbolMapper()
{
foreach (var mapping in FxcmSymbolMappings)
{
MapFxcmToLean[mapping.Item1] = mapping.Item2;
MapLeanToFxcm[mapping.Item2] = mapping.Item1;
}
}
/// <summary>
/// Converts a Lean symbol instance to an FXCM symbol
/// </summary>
/// <param name="symbol">A Lean symbol instance</param>
/// <returns>The FXCM symbol</returns>
public string GetBrokerageSymbol(Symbol symbol)
{
if (symbol == null || string.IsNullOrWhiteSpace(symbol.Value))
throw new ArgumentException("Invalid symbol: " + (symbol == null ? "null" : symbol.ToString()));
if (symbol.ID.SecurityType != SecurityType.Forex && symbol.ID.SecurityType != SecurityType.Cfd)
throw new ArgumentException("Invalid security type: " + symbol.ID.SecurityType);
var brokerageSymbol = ConvertLeanSymbolToFxcmSymbol(symbol.Value);
if (!IsKnownBrokerageSymbol(brokerageSymbol))
throw new ArgumentException("Unknown symbol: " + symbol.Value);
return brokerageSymbol;
}
/// <summary>
/// Converts an FXCM symbol to a Lean symbol instance
/// </summary>
/// <param name="brokerageSymbol">The FXCM symbol</param>
/// <param name="securityType">The security type</param>
/// <param name="market">The market</param>
/// <param name="expirationDate">Expiration date of the security(if applicable)</param>
/// <param name="strike">The strike of the security (if applicable)</param>
/// <param name="optionRight">The option right of the security (if applicable)</param>
/// <returns>A new Lean Symbol instance</returns>
public Symbol GetLeanSymbol(string brokerageSymbol, SecurityType securityType, string market, DateTime expirationDate = default(DateTime), decimal strike = 0, OptionRight optionRight = 0)
{
if (string.IsNullOrWhiteSpace(brokerageSymbol))
throw new ArgumentException("Invalid FXCM symbol: " + brokerageSymbol);
if (!IsKnownBrokerageSymbol(brokerageSymbol))
throw new ArgumentException("Unknown FXCM symbol: " + brokerageSymbol);
if (securityType != SecurityType.Forex && securityType != SecurityType.Cfd)
throw new ArgumentException("Invalid security type: " + securityType);
if (market != Market.FXCM)
throw new ArgumentException("Invalid market: " + market);
return Symbol.Create(ConvertFxcmSymbolToLeanSymbol(brokerageSymbol), GetBrokerageSecurityType(brokerageSymbol), Market.FXCM);
}
/// <summary>
/// Returns the security type for an FXCM symbol
/// </summary>
/// <param name="brokerageSymbol">The FXCM symbol</param>
/// <returns>The security type</returns>
public SecurityType GetBrokerageSecurityType(string brokerageSymbol)
{
var tokens = brokerageSymbol.Split('/');
return tokens.Length == 2 && KnownCurrencies.Contains(tokens[0]) && KnownCurrencies.Contains(tokens[1])
? SecurityType.Forex
: SecurityType.Cfd;
}
/// <summary>
/// Returns the security type for a Lean symbol
/// </summary>
/// <param name="leanSymbol">The Lean symbol</param>
/// <returns>The security type</returns>
public SecurityType GetLeanSecurityType(string leanSymbol)
{
string fxcmSymbol;
if (!MapLeanToFxcm.TryGetValue(leanSymbol, out fxcmSymbol))
throw new ArgumentException("Unknown Lean symbol: " + leanSymbol);
return GetBrokerageSecurityType(fxcmSymbol);
}
/// <summary>
/// Checks if the symbol is supported by FXCM
/// </summary>
/// <param name="brokerageSymbol">The FXCM symbol</param>
/// <returns>True if FXCM supports the symbol</returns>
public bool IsKnownBrokerageSymbol(string brokerageSymbol)
{
return brokerageSymbol != null && MapFxcmToLean.ContainsKey(brokerageSymbol);
}
/// <summary>
/// Checks if the symbol is supported by FXCM
/// </summary>
/// <param name="symbol">The Lean symbol</param>
/// <returns>True if FXCM supports the symbol</returns>
public bool IsKnownLeanSymbol(Symbol symbol)
{
if (symbol == null || string.IsNullOrWhiteSpace(symbol.Value))
return false;
var fxcmSymbol = ConvertLeanSymbolToFxcmSymbol(symbol.Value);
return MapFxcmToLean.ContainsKey(fxcmSymbol) && GetBrokerageSecurityType(fxcmSymbol) == symbol.ID.SecurityType;
}
/// <summary>
/// Converts an FXCM symbol to a Lean symbol string
/// </summary>
public static string ConvertFxcmSymbolToLeanSymbol(string fxcmSymbol)
{
string leanSymbol;
return MapFxcmToLean.TryGetValue(fxcmSymbol, out leanSymbol) ? leanSymbol : string.Empty;
}
/// <summary>
/// Converts a Lean symbol string to an FXCM symbol
/// </summary>
private static string ConvertLeanSymbolToFxcmSymbol(string leanSymbol)
{
string fxcmSymbol;
return MapLeanToFxcm.TryGetValue(leanSymbol, out fxcmSymbol) ? fxcmSymbol : string.Empty;
}
}
}

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Brokerages</RootNamespace>
<AssemblyName>QuantConnect.Brokerages</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>6</LangVersion>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<DefineConstants>NET45</DefineConstants>
@@ -32,7 +32,6 @@
</Target>
<ItemGroup>
<PackageReference Include="CsvHelper" Version="19.0.0" />
<PackageReference Include="IKVM" Version="8.1.5717.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -52,15 +51,6 @@
<Reference Include="CSharpAPI">
<HintPath>InteractiveBrokers\CSharpAPI.dll</HintPath>
</Reference>
<Reference Include="QuantConnect.Fxcm, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>Fxcm\QuantConnect.Fxcm.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Web" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
@@ -81,9 +71,4 @@
<ProjectReference Include="..\Configuration\QuantConnect.Configuration.csproj" />
<ProjectReference Include="..\Logging\QuantConnect.Logging.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="Fxcm\QuantConnect.Fxcm.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -13,8 +13,8 @@
* limitations under the License.
*/
using System.Linq;
using System.Collections.Generic;
using QuantConnect.Util;
namespace QuantConnect.Brokerages
{

View File

@@ -18,7 +18,6 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Securities.Future;
using QuantConnect.Util;
namespace QuantConnect.Data.Market
{

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<ProductVersion>8.0.30703</ProductVersion>
<AssemblyName>QuantConnect.Common</AssemblyName>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
@@ -100,24 +100,6 @@
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="5.0.0" />
<PackageReference Include="System.ServiceModel.Primitives" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Configuration" />
<Reference Include="System.IdentityModel" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.IdentityModel" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Numerics" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Configuration\QuantConnect.Configuration.csproj" />
<ProjectReference Include="..\Logging\QuantConnect.Logging.csproj" />

View File

@@ -203,7 +203,7 @@ namespace QuantConnect.Securities.Option.StrategyMatcher
/// </summary>
/// <returns></returns>
public OptionPosition GetUnderlyingPosition()
=> LinqExtensions.GetValueOrDefault(_positions, Underlying, new OptionPosition(Underlying, 0));
=> _positions.GetValueOrDefault(Underlying, new OptionPosition(Underlying, 0));
/// <summary>
/// Creates a new <see cref="OptionPositionCollection"/> from the specified enumerable of <paramref name="positions"/>

View File

@@ -61,17 +61,6 @@ namespace QuantConnect.Util
return new ReadOnlyDictionary<K, V>(enumerable.ToDictionary());
}
/// <summary>
/// Creates a new <see cref="HashSet{T}"/> from the elements in the specified enumerable
/// </summary>
/// <typeparam name="T">The item type in the hash set</typeparam>
/// <param name="enumerable">The items to be placed into the enumerable</param>
/// <returns>A new <see cref="HashSet{T}"/> containing the items in the enumerable</returns>
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> enumerable)
{
return new HashSet<T>(enumerable);
}
/// <summary>
/// Creates a new <see cref="HashSet{T}"/> from the elements in the specified enumerable
/// </summary>
@@ -347,21 +336,6 @@ namespace QuantConnect.Util
}
}
/// <summary>
/// Gets the value associated with the specified key or provided default value if key is not found.
/// </summary>
/// <typeparam name="K">The key type</typeparam>
/// <typeparam name="V">The value type</typeparam>
/// <param name="dictionary">The dictionary instance</param>
/// <param name="key">Lookup key</param>
/// <param name="defaultValue">Default value</param>
/// <returns>Value associated with the specified key or default value</returns>
public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dictionary, K key, V defaultValue = default(V))
{
V obj;
return dictionary.TryGetValue(key, out obj) ? obj : defaultValue;
}
/// <summary>
/// Performs an action for each element in collection source
/// </summary>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Compression</RootNamespace>
<AssemblyName>QuantConnect.Compression</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>6</LangVersion>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
@@ -37,11 +37,6 @@
</PackageReference>
<PackageReference Include="SharpZipLib" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.IO.Compression" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Configuration</RootNamespace>
<AssemblyName>QuantConnect.Configuration</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<LangVersion>6</LangVersion>
@@ -38,10 +38,6 @@
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -5,7 +5,7 @@
<ProductVersion>8.0.30703</ProductVersion>
<RootNamespace>QuantConnect.Lean.Engine</RootNamespace>
<AssemblyName>QuantConnect.Lean.Engine</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<PublishUrl>publish\</PublishUrl>
@@ -108,13 +108,6 @@
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Runtime.Caching" />
<Reference Include="System.Web" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Indicators</RootNamespace>
<AssemblyName>QuantConnect.Indicators</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>6</LangVersion>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
@@ -49,10 +49,6 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -5,7 +5,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>QuantConnect.Lean.Launcher</RootNamespace>
<AssemblyName>QuantConnect.Lean.Launcher</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>6</LangVersion>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
@@ -37,7 +37,6 @@
</Target>
<ItemGroup>
<PackageReference Include="DynamicInterop" Version="0.9.1" />
<PackageReference Include="IKVM" Version="8.1.5717.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -45,11 +44,6 @@
<PackageReference Include="R.NET" Version="1.9.0" />
<PackageReference Include="System.ComponentModel.Composition" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -5,7 +5,7 @@
<ProductVersion>8.0.30703</ProductVersion>
<RootNamespace>QuantConnect.Logging</RootNamespace>
<AssemblyName>QuantConnect.Logging</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<LangVersion>6</LangVersion>
@@ -57,10 +57,6 @@
</PackageReference>
<PackageReference Include="System.ComponentModel.Composition" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Messaging</RootNamespace>
<AssemblyName>QuantConnect.Messaging</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>6</LangVersion>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
@@ -40,12 +40,6 @@
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="RestSharp" Version="106.6.10" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.ServiceModel" />
<Reference Include="System.Web" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -5,7 +5,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>QuantConnect.Optimizer.Launcher</RootNamespace>
<AssemblyName>QuantConnect.Optimizer.Launcher</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
@@ -38,11 +38,6 @@
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Optimizer</RootNamespace>
<AssemblyName>QuantConnect.Optimizer</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<LangVersion>6</LangVersion>
@@ -40,11 +40,6 @@
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Queues</RootNamespace>
<AssemblyName>QuantConnect.Queues</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>6</LangVersion>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
@@ -36,10 +36,6 @@
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -5,7 +5,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>QuantConnect.Report</RootNamespace>
<AssemblyName>QuantConnect.Report</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
@@ -67,10 +67,6 @@
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Research</RootNamespace>
<AssemblyName>QuantConnect.Research</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>6</LangVersion>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<OutputPath>bin\$(Configuration)\</OutputPath>
@@ -52,10 +52,6 @@
<PackageReference Include="NodaTime" Version="3.0.5" />
<PackageReference Include="System.ComponentModel.Composition" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Algorithm.Framework\QuantConnect.Algorithm.Framework.csproj" />
<ProjectReference Include="..\Algorithm\QuantConnect.Algorithm.csproj" />

View File

@@ -24,7 +24,7 @@ using QuantConnect.Securities.Future;
using QuantConnect.Securities.Option;
using QuantConnect.Tests.Engine.DataFeeds;
using System;
using QuantConnect.Securities.Index;
using Index = QuantConnect.Securities.Index.Index;
namespace QuantConnect.Tests.Algorithm
{

View File

@@ -1,66 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using QuantConnect.Brokerages.Fxcm;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Logging;
namespace QuantConnect.Tests.Brokerages.Fxcm
{
[TestFixture]
public partial class FxcmBrokerageTests
{
[Test]
public void GetsTickData()
{
var brokerage = (FxcmBrokerage)Brokerage;
var cancelationToken = new CancellationTokenSource();
var configs = new SubscriptionDataConfig[] {
GetSubscriptionDataConfig<TradeBar>(Symbols.USDJPY, Resolution.Second),
GetSubscriptionDataConfig<TradeBar>(Symbols.EURGBP, Resolution.Second)
};
foreach (var config in configs)
{
ProcessFeed(
brokerage.Subscribe(config, (s, e) => { }),
cancelationToken,
(tick) => {
if (tick != null)
{
Log.Trace("{0}: {1} - {2} / {3}", tick.Time.ToStringInvariant("yyyy-MM-dd HH:mm:ss.fff"), tick.Symbol, (tick as Tick)?.BidPrice, (tick as Tick)?.AskPrice);
}
});
}
Thread.Sleep(5000);
foreach (var config in configs)
{
brokerage.Unsubscribe(config);
}
Thread.Sleep(20000);
cancelationToken.Cancel();
}
}
}

View File

@@ -1,165 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Diagnostics;
using System.Linq;
using NodaTime;
using NUnit.Framework;
using QuantConnect.Brokerages.Fxcm;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Lean.Engine.HistoricalData;
using QuantConnect.Logging;
using QuantConnect.Securities;
namespace QuantConnect.Tests.Brokerages.Fxcm
{
[TestFixture]
public partial class FxcmBrokerageTests
{
private static TestCaseData[] TestParameters
{
get
{
return new[]
{
// valid parameters
new TestCaseData(Symbols.EURUSD, Resolution.Tick, TimeSpan.FromSeconds(15), false),
new TestCaseData(Symbols.EURUSD, Resolution.Second, Time.OneMinute, false),
new TestCaseData(Symbols.EURUSD, Resolution.Minute, Time.OneHour, false),
new TestCaseData(Symbols.EURUSD, Resolution.Hour, Time.OneDay, false),
new TestCaseData(Symbols.EURUSD, Resolution.Daily, TimeSpan.FromDays(15), false),
// invalid period, no error, empty result
new TestCaseData(Symbols.EURUSD, Resolution.Daily, TimeSpan.FromDays(-15), false),
// invalid symbol, throws "System.ArgumentException : Unknown symbol: XYZ"
new TestCaseData(Symbol.Create("XYZ", SecurityType.Forex, Market.FXCM), Resolution.Daily, TimeSpan.FromDays(15), true),
// invalid security type, throws "System.ArgumentException : Invalid security type: Equity"
new TestCaseData(Symbols.AAPL, Resolution.Daily, TimeSpan.FromDays(15), true),
};
}
}
[Test, TestCaseSource(nameof(TestParameters))]
public void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, bool throwsException)
{
TestDelegate test = () =>
{
var brokerage = (FxcmBrokerage) Brokerage;
var historyProvider = new BrokerageHistoryProvider();
historyProvider.SetBrokerage(brokerage);
historyProvider.Initialize(new HistoryProviderInitializeParameters(null, null, null, null, null, null, null, false, null));
var now = DateTime.UtcNow;
var requests = new[]
{
new HistoryRequest(now.Add(-period),
now,
typeof(QuoteBar),
symbol,
resolution,
SecurityExchangeHours.AlwaysOpen(TimeZones.Utc),
DateTimeZone.Utc,
Resolution.Minute,
false,
false,
DataNormalizationMode.Adjusted,
TickType.Quote)
};
var history = historyProvider.GetHistory(requests, TimeZones.Utc);
foreach (var slice in history)
{
if (resolution == Resolution.Tick)
{
foreach (var tick in slice.Ticks[symbol])
{
Log.Trace("{0}: {1} - {2} / {3}", tick.Time.ToStringInvariant("yyyy-MM-dd HH:mm:ss.fff"), tick.Symbol, tick.BidPrice, tick.AskPrice);
}
}
else
{
var bar = slice.Bars[symbol];
Log.Trace("{0}: {1} - O={2}, H={3}, L={4}, C={5}", bar.Time, bar.Symbol, bar.Open, bar.High, bar.Low, bar.Close);
}
}
Log.Trace("Data points retrieved: " + historyProvider.DataPointCount);
};
if (throwsException)
{
Assert.Throws<ArgumentException>(test);
}
else
{
Assert.DoesNotThrow(test);
}
}
[Test]
public void GetsFullDayTickHistory()
{
var symbol = Symbols.EURUSD;
const Resolution resolution = Resolution.Tick;
var startDate = new DateTime(2016, 11, 1);
var endDate = startDate.AddDays(1);
var brokerage = (FxcmBrokerage)Brokerage;
var historyProvider = new BrokerageHistoryProvider();
historyProvider.SetBrokerage(brokerage);
historyProvider.Initialize(new HistoryProviderInitializeParameters(null, null, null, null, null, null, null, false, null));
var stopwatch = Stopwatch.StartNew();
var requests = new[]
{
new HistoryRequest(startDate,
endDate,
typeof(QuoteBar),
symbol,
resolution,
SecurityExchangeHours.AlwaysOpen(TimeZones.Utc),
DateTimeZone.Utc,
Resolution.Minute,
false,
false,
DataNormalizationMode.Adjusted,
TickType.Quote)
};
var history = historyProvider.GetHistory(requests, TimeZones.Utc);
var tickCount = history.SelectMany(slice => slice.Ticks[symbol]).Count();
stopwatch.Stop();
Log.Trace("Download time: " + stopwatch.Elapsed);
Log.Trace("History ticks returned: " + tickCount);
Log.Trace("Data points retrieved: " + historyProvider.DataPointCount);
Assert.AreEqual(tickCount, historyProvider.DataPointCount);
Assert.AreEqual(241233, tickCount);
}
}
}

View File

@@ -1,226 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using NUnit.Framework;
using QuantConnect.Brokerages.Fxcm;
using QuantConnect.Configuration;
using QuantConnect.Interfaces;
using QuantConnect.Lean.Engine.DataFeeds;
using QuantConnect.Logging;
using QuantConnect.Orders;
using QuantConnect.Securities;
namespace QuantConnect.Tests.Brokerages.Fxcm
{
[TestFixture, Ignore("These tests require a configured and active FXCM practice account")]
public partial class FxcmBrokerageTests : BrokerageTests
{
/// <summary>
/// Creates the brokerage under test
/// </summary>
/// <returns>A connected brokerage instance</returns>
protected override IBrokerage CreateBrokerage(IOrderProvider orderProvider, ISecurityProvider securityProvider)
{
var server = Config.Get("fxcm-server");
var terminal = Config.Get("fxcm-terminal");
var userName = Config.Get("fxcm-user-name");
var password = Config.Get("fxcm-password");
var accountId = Config.Get("fxcm-account-id");
return new FxcmBrokerage(orderProvider, securityProvider, new AggregationManager(), server, terminal, userName, password, accountId);
}
/// <summary>
/// Disposes of the brokerage and any external resources started in order to create it
/// </summary>
/// <param name="brokerage">The brokerage instance to be disposed of</param>
protected override void DisposeBrokerage(IBrokerage brokerage)
{
brokerage.Disconnect();
}
/// <summary>
/// Provides the data required to test each order type in various cases
/// </summary>
public static TestCaseData[] OrderParameters
{
get
{
return new[]
{
new TestCaseData(new MarketOrderTestParameters(Symbols.EURUSD)).SetName("MarketOrder"),
new TestCaseData(new FxcmLimitOrderTestParameters(Symbols.EURUSD, 1.5m, 0.7m)).SetName("LimitOrder"),
new TestCaseData(new FxcmStopMarketOrderTestParameters(Symbols.EURUSD, 1.5m, 0.7m)).SetName("StopMarketOrder"),
};
}
}
/// <summary>
/// Gets the symbol to be traded, must be shortable
/// </summary>
protected override Symbol Symbol => Symbols.EURUSD;
/// <summary>
/// Gets the security type associated with the <see cref="BrokerageTests.Symbol"/>
/// </summary>
protected override SecurityType SecurityType => SecurityType.Forex;
/// <summary>
/// Returns wether or not the brokers order methods implementation are async
/// </summary>
protected override bool IsAsync()
{
return false;
}
/// <summary>
/// Gets the current market price of the specified security
/// </summary>
protected override decimal GetAskPrice(Symbol symbol)
{
// not used, we use bid/ask prices
return 0;
}
/// <summary>
/// Gets the default order quantity
/// </summary>
protected override decimal GetDefaultQuantity()
{
// FXCM requires a multiple of 1000 for Forex instruments
return 1000;
}
[Test, Ignore("This test requires disconnecting the internet to test for connection resiliency")]
public void ClientReconnectsAfterInternetDisconnect()
{
var brokerage = Brokerage;
Assert.IsTrue(brokerage.IsConnected);
var tenMinutes = TimeSpan.FromMinutes(10);
Log.Trace("------");
Log.Trace("Waiting for internet disconnection ");
Log.Trace("------");
// spin while we manually disconnect the internet
while (brokerage.IsConnected)
{
Thread.Sleep(2500);
Console.Write(".");
}
var stopwatch = Stopwatch.StartNew();
Log.Trace("------");
Log.Trace("Trying to reconnect ");
Log.Trace("------");
// spin until we're reconnected
while (!brokerage.IsConnected && stopwatch.Elapsed < tenMinutes)
{
Thread.Sleep(2500);
Console.Write(".");
}
Assert.IsTrue(brokerage.IsConnected);
}
[TestCase("EURGBP", SecurityType.Forex, Market.FXCM, 50000)]
[TestCase("EURGBP", SecurityType.Forex, Market.FXCM, -50000)]
[TestCase("DE30EUR", SecurityType.Cfd, Market.FXCM, 10)]
[TestCase("DE30EUR", SecurityType.Cfd, Market.FXCM, -10)]
public void GetCashBalanceIncludesCurrencySwapsForOpenPositions(string ticker, SecurityType securityType, string market, decimal quantity)
{
// This test requires a practice account with USD account currency
var brokerage = Brokerage;
Assert.IsTrue(brokerage.IsConnected);
var symbol = Symbol.Create(ticker, securityType, market);
var order = new MarketOrder(symbol, quantity, DateTime.UtcNow);
PlaceOrderWaitForStatus(order);
var holdings = brokerage.GetAccountHoldings();
var balances = brokerage.GetCashBalance();
Assert.IsTrue(holdings.Count == 1);
// account currency
Assert.IsTrue(balances.Any(x => x.Currency == "USD"));
if (securityType == SecurityType.Forex)
{
// base currency
var baseCurrencyCash = balances.Single(x => x.Currency == ticker.Substring(0, 3));
Assert.AreEqual(quantity, baseCurrencyCash.Amount);
// quote currency
var quoteCurrencyCash = balances.Single(x => x.Currency == ticker.Substring(3));
Assert.AreEqual(-Math.Sign(quantity), Math.Sign(quoteCurrencyCash.Amount));
}
else if (securityType == SecurityType.Cfd)
{
Assert.AreEqual(1, balances.Count);
}
}
[Test, TestCaseSource(nameof(OrderParameters))]
public override void CancelOrders(OrderTestParameters parameters)
{
base.CancelOrders(parameters);
}
[Test, TestCaseSource(nameof(OrderParameters))]
public override void LongFromZero(OrderTestParameters parameters)
{
base.LongFromZero(parameters);
}
[Test, TestCaseSource(nameof(OrderParameters))]
public override void CloseFromLong(OrderTestParameters parameters)
{
base.CloseFromLong(parameters);
}
[Test, TestCaseSource(nameof(OrderParameters))]
public override void ShortFromZero(OrderTestParameters parameters)
{
base.ShortFromZero(parameters);
}
[Test, TestCaseSource(nameof(OrderParameters))]
public override void CloseFromShort(OrderTestParameters parameters)
{
base.CloseFromShort(parameters);
}
[Test, TestCaseSource(nameof(OrderParameters))]
public override void ShortFromLong(OrderTestParameters parameters)
{
base.ShortFromLong(parameters);
}
[Test, TestCaseSource(nameof(OrderParameters))]
public override void LongFromShort(OrderTestParameters parameters)
{
base.LongFromShort(parameters);
}
}
}

View File

@@ -1,64 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Brokerages.Fxcm;
using QuantConnect.Interfaces;
using QuantConnect.Logging;
using QuantConnect.Orders;
namespace QuantConnect.Tests.Brokerages.Fxcm
{
public class FxcmLimitOrderTestParameters : LimitOrderTestParameters
{
public FxcmLimitOrderTestParameters(Symbol symbol, decimal highLimit, decimal lowLimit)
: base(symbol, highLimit, lowLimit)
{
}
public override bool ModifyOrderToFill(IBrokerage brokerage, Order order, decimal lastMarketPrice)
{
// FXCM Buy Limit orders will be rejected if the limit price is above the market price
// FXCM Sell Limit orders will be rejected if the limit price is below the market price
var limit = (LimitOrder)order;
var previousLimit = limit.LimitPrice;
var fxcmBrokerage = (FxcmBrokerage)brokerage;
var quotes = fxcmBrokerage.GetBidAndAsk(new List<string> { new FxcmSymbolMapper().GetBrokerageSymbol(order.Symbol) });
if (order.Quantity > 0)
{
// for limit buys we need to increase the limit price
// buy limit price must be at bid price or below
var bidPrice = Convert.ToDecimal(quotes.Single().BidPrice);
Log.Trace("FxcmLimitOrderTestParameters.ModifyOrderToFill(): Bid: " + bidPrice);
limit.LimitPrice = Math.Max(previousLimit, Math.Min(bidPrice, limit.LimitPrice * 2));
}
else
{
// for limit sells we need to decrease the limit price
// sell limit price must be at ask price or above
var askPrice = Convert.ToDecimal(quotes.Single().AskPrice);
Log.Trace("FxcmLimitOrderTestParameters.ModifyOrderToFill(): Ask: " + askPrice);
limit.LimitPrice = Math.Min(previousLimit, Math.Max(askPrice, limit.LimitPrice / 2));
}
return limit.LimitPrice != previousLimit;
}
}
}

View File

@@ -1,64 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Brokerages.Fxcm;
using QuantConnect.Interfaces;
using QuantConnect.Logging;
using QuantConnect.Orders;
namespace QuantConnect.Tests.Brokerages.Fxcm
{
public class FxcmStopMarketOrderTestParameters : StopMarketOrderTestParameters
{
public FxcmStopMarketOrderTestParameters(Symbol symbol, decimal highLimit, decimal lowLimit)
: base(symbol, highLimit, lowLimit)
{
}
public override bool ModifyOrderToFill(IBrokerage brokerage, Order order, decimal lastMarketPrice)
{
// FXCM Buy StopMarket orders will be rejected if the stop price is below the market price
// FXCM Sell StopMarket orders will be rejected if the stop price is above the market price
var stop = (StopMarketOrder)order;
var previousStop = stop.StopPrice;
var fxcmBrokerage = (FxcmBrokerage)brokerage;
var quotes = fxcmBrokerage.GetBidAndAsk(new List<string> { new FxcmSymbolMapper().GetBrokerageSymbol(order.Symbol) });
if (order.Quantity > 0)
{
// for stop buys we need to decrease the stop price
// buy stop price must be strictly above ask price
var askPrice = Convert.ToDecimal(quotes.Single().AskPrice);
Log.Trace("FxcmStopMarketOrderTestParameters.ModifyOrderToFill(): Ask: " + askPrice);
stop.StopPrice = Math.Min(previousStop, Math.Max(askPrice, stop.StopPrice / 2) + 0.00001m);
}
else
{
// for stop sells we need to increase the stop price
// sell stop price must be strictly below bid price
var bidPrice = Convert.ToDecimal(quotes.Single().BidPrice);
Log.Trace("FxcmStopMarketOrderTestParameters.ModifyOrderToFill(): Bid: " + bidPrice);
stop.StopPrice = Math.Max(previousStop, Math.Min(bidPrice, stop.StopPrice * 2) - 0.00001m);
}
return stop.StopPrice != previousStop;
}
}
}

View File

@@ -1,120 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using NUnit.Framework;
using QuantConnect.Brokerages.Fxcm;
namespace QuantConnect.Tests.Brokerages.Fxcm
{
[TestFixture]
public class FxcmSymbolMapperTests
{
[Test]
public void ReturnsCorrectLeanSymbol()
{
var mapper = new FxcmSymbolMapper();
var symbol = mapper.GetLeanSymbol("EUR/USD", SecurityType.Forex, Market.FXCM);
Assert.AreEqual("EURUSD", symbol.Value);
Assert.AreEqual(SecurityType.Forex, symbol.ID.SecurityType);
Assert.AreEqual(Market.FXCM, symbol.ID.Market);
symbol = mapper.GetLeanSymbol("GER30", SecurityType.Cfd, Market.FXCM);
Assert.AreEqual("DE30EUR", symbol.Value);
Assert.AreEqual(SecurityType.Cfd, symbol.ID.SecurityType);
Assert.AreEqual(Market.FXCM, symbol.ID.Market);
}
[Test]
public void ReturnsCorrectBrokerageSymbol()
{
var mapper = new FxcmSymbolMapper();
var symbol = Symbol.Create("EURUSD", SecurityType.Forex, Market.FXCM);
var brokerageSymbol = mapper.GetBrokerageSymbol(symbol);
Assert.AreEqual("EUR/USD", brokerageSymbol);
symbol = Symbol.Create("DE30EUR", SecurityType.Cfd, Market.FXCM);
brokerageSymbol = mapper.GetBrokerageSymbol(symbol);
Assert.AreEqual("GER30", brokerageSymbol);
}
[Test]
public void ThrowsOnNullOrEmptySymbol()
{
var mapper = new FxcmSymbolMapper();
Assert.Throws<ArgumentException>(() => mapper.GetLeanSymbol(null, SecurityType.Forex, Market.FXCM));
Assert.Throws<ArgumentException>(() => mapper.GetLeanSymbol("", SecurityType.Forex, Market.FXCM));
var symbol = Symbol.Empty;
Assert.Throws<ArgumentException>(() => mapper.GetBrokerageSymbol(symbol));
symbol = null;
Assert.Throws<ArgumentException>(() => mapper.GetBrokerageSymbol(symbol));
symbol = Symbol.Create("", SecurityType.Forex, Market.FXCM);
Assert.Throws<ArgumentException>(() => mapper.GetBrokerageSymbol(symbol));
}
[Test]
public void ThrowsOnUnknownSymbol()
{
var mapper = new FxcmSymbolMapper();
Assert.Throws<ArgumentException>(() => mapper.GetLeanSymbol("ABC/USD", SecurityType.Forex, Market.FXCM));
var symbol = Symbol.Create("ABCUSD", SecurityType.Forex, Market.FXCM);
Assert.Throws<ArgumentException>(() => mapper.GetBrokerageSymbol(symbol));
}
[Test]
public void ThrowsOnInvalidSecurityType()
{
var mapper = new FxcmSymbolMapper();
Assert.Throws<ArgumentException>(() => mapper.GetLeanSymbol("AAPL", SecurityType.Equity, Market.FXCM));
var symbol = Symbol.Create("AAPL", SecurityType.Equity, Market.FXCM);
Assert.Throws<ArgumentException>(() => mapper.GetBrokerageSymbol(symbol));
}
[Test]
public void ChecksForKnownSymbols()
{
#pragma warning disable 0618 // This test requires implicit operators
var mapper = new FxcmSymbolMapper();
Assert.IsFalse(mapper.IsKnownBrokerageSymbol(null));
Assert.IsFalse(mapper.IsKnownBrokerageSymbol(""));
Assert.IsTrue(mapper.IsKnownBrokerageSymbol("EUR/USD"));
Assert.IsTrue(mapper.IsKnownBrokerageSymbol("GER30"));
Assert.IsFalse(mapper.IsKnownBrokerageSymbol("ABC/USD"));
Assert.IsFalse(mapper.IsKnownLeanSymbol(null));
Assert.IsFalse(mapper.IsKnownLeanSymbol(""));
Assert.IsFalse(mapper.IsKnownLeanSymbol(Symbol.Empty));
Assert.IsTrue(mapper.IsKnownLeanSymbol(Symbol.Create("EURUSD", SecurityType.Forex, Market.FXCM)));
Assert.IsFalse(mapper.IsKnownLeanSymbol(Symbol.Create("ABCUSD", SecurityType.Forex, Market.FXCM)));
Assert.IsFalse(mapper.IsKnownLeanSymbol(Symbol.Create("EURUSD", SecurityType.Cfd, Market.FXCM)));
Assert.IsFalse(mapper.IsKnownLeanSymbol(Symbol.Create("DE30EUR", SecurityType.Forex, Market.FXCM)));
#pragma warning restore 0618
}
}
}

View File

@@ -15,6 +15,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Market;

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Tests</RootNamespace>
<AssemblyName>QuantConnect.Tests</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<LangVersion>6</LangVersion>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
@@ -55,7 +55,6 @@
<PackageReference Include="Common.Logging.Core" Version="3.4.1" />
<PackageReference Include="Deedle" Version="2.1.0" />
<PackageReference Include="DotNetZip" Version="1.13.3" />
<PackageReference Include="IKVM" Version="8.1.5717.0" />
<PackageReference Include="LaunchDarkly.EventSource" Version="3.3.2" />
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.6.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3">
@@ -108,13 +107,6 @@
<HintPath>..\Brokerages\Fxcm\QuantConnect.Fxcm.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="System.Configuration" />
<Reference Include="System.IdentityModel" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Web" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />

View File

@@ -1,168 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using NUnit.Framework;
using QuantConnect.Data.Custom;
using QuantConnect.ToolBox;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
namespace QuantConnect.Tests.ToolBox
{
/// <summary>
/// The rationality is to test the main functionalities:
/// - Data is correctly parsed.
/// - Data is correctly saved.
/// </summary>
[TestFixture, Ignore("FXCM API goes down on weekends")]
public class FxcmVolumeDownloaderTest
{
private string _dataDirectory;
private List<string> _testingTempFolders = new List<string>();
private FxcmVolumeDownloader _downloader;
private readonly Symbol _eurusd = Symbol.Create("EURUSD", SecurityType.Base, Market.FXCM);
[SetUp]
public void SetUpTemporatyFolder()
{
var randomFolder = Guid.NewGuid().ToStringInvariant("N").Substring(startIndex: 0, length: 8);
var assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
_dataDirectory = Path.Combine(assemblyFolder, randomFolder);
_downloader = new FxcmVolumeDownloader(_dataDirectory);
_testingTempFolders.Add(_dataDirectory);
}
[TearDown]
public void CleanTemporaryFolder()
{
foreach (var testingTempFolder in _testingTempFolders)
{
if (Directory.Exists(testingTempFolder))
{
Directory.Delete(testingTempFolder, true);
}
}
}
[TestCase("./TestData/fxVolumeDaily.csv", "EURUSD", Resolution.Daily, "2016-12-01", "2017-01-30")]
[TestCase("./TestData/fxVolumeHourly.csv", "USDJPY", Resolution.Hour, "2014-12-24", "2015-01-05")]
[TestCase("./TestData/fxVolumeMinute.csv", "EURUSD", Resolution.Minute, "2012-11-23", "2012-11-27")]
public void DataIsCorrectlyParsed(string testingFilePath, string ticker, Resolution resolution, string startDate, string endDate)
{
//Arrange
var expectedData = File.ReadAllLines(testingFilePath)
.Skip(count: 1) // Skip headers.
.Select(x => x.Split(','))
.ToArray();
var symbol = Symbol.Create(ticker, SecurityType.Base, Market.FXCM);
var startUtc = Parse.DateTimeExact(startDate, "yyyy-MM-dd");
var endUtc = Parse.DateTimeExact(endDate, "yyyy-MM-dd");
//Act
var actualData = _downloader.Get(symbol, resolution, startUtc,
endUtc).Cast<FxcmVolume>().ToArray();
//Assert
Assert.AreEqual(expectedData.Length, actualData.Length);
for (var i = 0; i < expectedData.Length - 1; i++)
{
Assert.AreEqual(expectedData[i][0], actualData[i].Time.ToStringInvariant("yyyy/MM/dd HH:mm"));
Assert.AreEqual(expectedData[i][1], actualData[i].Value.ToString(CultureInfo.InvariantCulture));
Assert.AreEqual(expectedData[i][2], actualData[i].Transactions.ToString(CultureInfo.InvariantCulture));
}
}
[TestCase("GBPUSD", Resolution.Daily, "2015-11-27", 20)]
[TestCase("USDCAD", Resolution.Hour, "2016-09-15", 5)]
[TestCase("EURJPY", Resolution.Minute, "2015-01-26", 2)]
public void ParsedDataIsCorrectlySaved(string ticker, Resolution resolution, string startDate, int requestLength)
{
// Arrange
var symbol = Symbol.Create(ticker, SecurityType.Base, Market.FXCM);
var startUtc = Parse.DateTimeExact(startDate, "yyyy-MM-dd");
var endUtc = startUtc.AddDays(requestLength);
var data = _downloader.Get(symbol, resolution, startUtc, endUtc);
// Act
var writer = new FxcmVolumeWriter(resolution, symbol, _dataDirectory);
writer.Write(data);
// Assert
var expectedData = data.Cast<FxcmVolume>().ToArray();
var expectedFolder = Path.Combine(_dataDirectory, $"forex/fxcm/{resolution.ToLower()}");
if (resolution == Resolution.Minute)
{
expectedFolder = Path.Combine(expectedFolder, symbol.Value.ToLowerInvariant());
}
Assert.True(Directory.Exists(expectedFolder));
if (resolution == Resolution.Minute)
{
var zipFiles = Directory.GetFiles(expectedFolder, "*_volume.zip").Length;
// Minus one because the Downloader starts one day earlier.
Assert.AreEqual(requestLength + 1, zipFiles);
}
else
{
var expectedFilename = $"{symbol.Value.ToLowerInvariant()}_volume.zip";
Assert.True(File.Exists(Path.Combine(expectedFolder, expectedFilename)));
}
var actualdata = FxcmVolumeAuxiliaryMethods.ReadZipFolderData(expectedFolder);
Assert.AreEqual(expectedData.Length, actualdata.Count);
var lines = actualdata.Count;
for (var i = 0; i < lines - 1; i++)
{
Assert.AreEqual(expectedData[i].Value, Parse.Long(actualdata[i][1]));
Assert.AreEqual(expectedData[i].Transactions, Parse.Int(actualdata[i][2]));
}
}
[Ignore("Long test")]
[Test]
public void RequestWithMoreThan10KMinuteObservationIsCorrectlySaved()
{
// Arrange
var resolution = Resolution.Minute;
var startDate = new DateTime(year: 2013, month: 04, day: 01);
var endDate = startDate.AddMonths(months: 1);
// Act
_downloader.Run(_eurusd, resolution, startDate, endDate);
// Assert
var outputFolder = Path.Combine(_dataDirectory, "forex/fxcm/minute");
var files = Directory.GetFiles(outputFolder, "*_volume.zip", SearchOption.AllDirectories);
Assert.AreEqual(expected: 27, actual: files.Length);
}
[Ignore("Long test")]
[Test]
public void RequestWithMoreThan10KHourlyObservationIsCorrectlySaved()
{
// Arrange
var resolution = Resolution.Hour;
var startDate = new DateTime(year: 2014, month: 01, day: 01);
var endDate = startDate.AddYears(value: 3);
// Act
_downloader.Run(_eurusd, resolution, startDate, endDate);
// Assert
var outputFile = Path.Combine(_dataDirectory, "forex/fxcm/hour/eurusd_volume.zip");
var observationsCount = FxcmVolumeAuxiliaryMethods.ReadZipFileData(outputFile).Count;
// 3 years x 52 weeks x 5 days x 24 hours = 18720 hours at least.
Assert.True(observationsCount >= 18720, $"Actual observations: {observationsCount}");
}
}
}

View File

@@ -1,385 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using com.fxcm.external.api.transport;
using com.fxcm.external.api.transport.listeners;
using com.fxcm.fix;
using com.fxcm.fix.pretrade;
using com.fxcm.messaging;
using java.util;
using QuantConnect.Brokerages.Fxcm;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using TimeZone = java.util.TimeZone;
namespace QuantConnect.ToolBox.FxcmDownloader
{
/// <summary>
/// FXCM Data Downloader class
/// </summary>
public class FxcmDataDownloader : IDataDownloader, IGenericMessageListener, IStatusMessageListener
{
private readonly FxcmSymbolMapper _symbolMapper = new FxcmSymbolMapper();
private readonly string _server;
private readonly string _terminal;
private readonly string _userName;
private readonly string _password;
private IGateway _gateway;
private readonly object _locker = new object();
private string _currentRequest;
private const int ResponseTimeout = 2500;
private readonly Dictionary<string, AutoResetEvent> _mapRequestsToAutoResetEvents = new Dictionary<string, AutoResetEvent>();
private readonly Dictionary<string, TradingSecurity> _fxcmInstruments = new Dictionary<string, TradingSecurity>();
private readonly IList<BaseData> _currentBaseData = new List<BaseData>();
/// <summary>
/// Initializes a new instance of the <see cref="FxcmDataDownloader"/> class
/// </summary>
public FxcmDataDownloader(string server, string terminal, string userName, string password)
{
_server = server;
_terminal = terminal;
_userName = userName;
_password = password;
}
/// <summary>
/// Converts a Java Date value to a UTC DateTime value
/// </summary>
/// <param name="javaDate">The Java date</param>
/// <returns>A UTC DateTime value</returns>
private static DateTime FromJavaDateUtc(Date javaDate)
{
var cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("UTC"));
cal.setTime(javaDate);
// note that the Month component of java.util.Date
// from 0-11 (i.e. Jan == 0)
return new DateTime(cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH) + 1,
cal.get(Calendar.DAY_OF_MONTH),
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
cal.get(Calendar.SECOND),
cal.get(Calendar.MILLISECOND));
}
/// <summary>
/// Checks if downloader can get the data for the Lean symbol
/// </summary>
/// <param name="symbol">The Lean symbol</param>
/// <returns>Returns true if the symbol is available</returns>
public bool HasSymbol(string symbol)
{
return _symbolMapper.IsKnownLeanSymbol(Symbol.Create(symbol, GetSecurityType(symbol), Market.FXCM));
}
/// <summary>
/// Gets the security type for the specified Lean symbol
/// </summary>
/// <param name="symbol">The Lean symbol</param>
/// <returns>The security type</returns>
public SecurityType GetSecurityType(string symbol)
{
return _symbolMapper.GetLeanSecurityType(symbol);
}
/// <summary>
/// Get historical data enumerable for a single symbol, type and resolution given this start and end time (in UTC).
/// </summary>
/// <param name="symbol">Symbol for the data we're looking for.</param>
/// <param name="resolution">Resolution of the data request</param>
/// <param name="startUtc">Start time of the data in UTC</param>
/// <param name="endUtc">End time of the data in UTC</param>
/// <returns>Enumerable of base data for this symbol</returns>
public IEnumerable<BaseData> Get(Symbol symbol, Resolution resolution, DateTime startUtc, DateTime endUtc)
{
if (!_symbolMapper.IsKnownLeanSymbol(symbol))
throw new ArgumentException("Invalid symbol requested: " + symbol.Value);
if (symbol.ID.SecurityType != SecurityType.Forex && symbol.ID.SecurityType != SecurityType.Cfd)
throw new NotSupportedException("SecurityType not available: " + symbol.ID.SecurityType);
if (endUtc <= startUtc)
throw new ArgumentException("The end date must be greater than the start date.");
Console.WriteLine("Logging in...");
// create the gateway
_gateway = GatewayFactory.createGateway();
// register the message listeners with the gateway
_gateway.registerGenericMessageListener(this);
_gateway.registerStatusMessageListener(this);
// create local login properties
var loginProperties = new FXCMLoginProperties(_userName, _password, _terminal, _server);
// log in
_gateway.login(loginProperties);
// initialize session
RequestTradingSessionStatus();
Console.WriteLine($"Downloading {resolution.ToStringInvariant()} data from {startUtc.ToStringInvariant("yyyyMMdd HH:mm:ss")} to {endUtc.ToStringInvariant("yyyyMMdd HH:mm:ss")}...");
// Find best FXCM parameters
var interval = FxcmBrokerage.ToFxcmInterval(resolution);
var totalTicks = (endUtc - startUtc).Ticks;
// download data
var totalBaseData = new List<BaseData>();
var end = endUtc;
do //
{
//show progress
progressBar(Math.Abs((end - endUtc).Ticks), totalTicks, Console.WindowWidth / 2,'█');
_currentBaseData.Clear();
var mdr = new MarketDataRequest();
mdr.setSubscriptionRequestType(SubscriptionRequestTypeFactory.SNAPSHOT);
mdr.setResponseFormat(IFixMsgTypeDefs.__Fields.MSGTYPE_FXCMRESPONSE);
mdr.setFXCMTimingInterval(interval);
mdr.setMDEntryTypeSet(MarketDataRequest.MDENTRYTYPESET_ALL);
mdr.setFXCMStartDate(new UTCDate(FxcmBrokerage.ToJavaDateUtc(startUtc)));
mdr.setFXCMStartTime(new UTCTimeOnly(FxcmBrokerage.ToJavaDateUtc(startUtc)));
mdr.setFXCMEndDate(new UTCDate(FxcmBrokerage.ToJavaDateUtc(end)));
mdr.setFXCMEndTime(new UTCTimeOnly(FxcmBrokerage.ToJavaDateUtc(end)));
mdr.addRelatedSymbol(_fxcmInstruments[_symbolMapper.GetBrokerageSymbol(symbol)]);
AutoResetEvent autoResetEvent;
lock (_locker)
{
_currentRequest = _gateway.sendMessage(mdr);
autoResetEvent = new AutoResetEvent(false);
_mapRequestsToAutoResetEvents[_currentRequest] = autoResetEvent;
}
if (!autoResetEvent.WaitOne(1000 * 5))
{
// no response, exit
break;
}
// Add data
totalBaseData.InsertRange(0, _currentBaseData.Where(x => x.Time.Date >= startUtc.Date));
if (end != _currentBaseData[0].Time)
{
// new end date = first datapoint date.
end = _currentBaseData[0].Time;
}
else
{
break;
}
} while (end > startUtc);
Console.WriteLine("\nLogging out...");
// log out
_gateway.logout();
// remove the message listeners
_gateway.removeGenericMessageListener(this);
_gateway.removeStatusMessageListener(this);
return totalBaseData.ToList();
}
private void RequestTradingSessionStatus()
{
// Note: requestTradingSessionStatus() MUST be called just after login
AutoResetEvent autoResetEvent;
lock (_locker)
{
_currentRequest = _gateway.requestTradingSessionStatus();
autoResetEvent = new AutoResetEvent(false);
_mapRequestsToAutoResetEvents[_currentRequest] = autoResetEvent;
}
if (!autoResetEvent.WaitOne(ResponseTimeout))
throw new TimeoutException("FxcmBrokerage.LoadInstruments(): Operation took " +
$"longer than {((decimal) ResponseTimeout / 1000).ToStringInvariant()} seconds."
);
}
#region IGenericMessageListener implementation
/// <summary>
/// Receives generic messages from the FXCM API
/// </summary>
/// <param name="message">Generic message received</param>
public void messageArrived(ITransportable message)
{
// Dispatch message to specific handler
lock (_locker)
{
if (message is TradingSessionStatus)
OnTradingSessionStatus((TradingSessionStatus)message);
else if (message is MarketDataSnapshot)
OnMarketDataSnapshot((MarketDataSnapshot)message);
}
}
/// <summary>
/// TradingSessionStatus message handler
/// </summary>
private void OnTradingSessionStatus(TradingSessionStatus message)
{
if (message.getRequestID() == _currentRequest)
{
// load instrument list into a dictionary
var securities = message.getSecurities();
while (securities.hasMoreElements())
{
var security = (TradingSecurity)securities.nextElement();
_fxcmInstruments[security.getSymbol()] = security;
}
_mapRequestsToAutoResetEvents[_currentRequest].Set();
_mapRequestsToAutoResetEvents.Remove(_currentRequest);
}
}
/// <summary>
/// MarketDataSnapshot message handler
/// </summary>
private void OnMarketDataSnapshot(MarketDataSnapshot message)
{
if (message.getRequestID() == _currentRequest)
{
var securityType = _symbolMapper.GetBrokerageSecurityType(message.getInstrument().getSymbol());
var symbol = _symbolMapper.GetLeanSymbol(message.getInstrument().getSymbol(), securityType, Market.FXCM);
var time = FromJavaDateUtc(message.getDate().toDate());
if (message.getFXCMTimingInterval() == FXCMTimingIntervalFactory.TICK)
{
var bid = Convert.ToDecimal(message.getBidClose());
var ask = Convert.ToDecimal(message.getAskClose());
var tick = new Tick(time, symbol, bid, ask);
//Add tick
_currentBaseData.Add(tick);
}
else // it bars
{
var open = Convert.ToDecimal((message.getBidOpen() + message.getAskOpen()) / 2);
var high = Convert.ToDecimal((message.getBidHigh() + message.getAskHigh()) / 2);
var low = Convert.ToDecimal((message.getBidLow() + message.getAskLow()) / 2);
var close = Convert.ToDecimal((message.getBidClose() + message.getAskClose()) / 2);
var bar = new TradeBar(time, symbol, open, high, low, close, 0);
// add bar to list
_currentBaseData.Add(bar);
}
if (message.getFXCMContinuousFlag() == IFixValueDefs.__Fields.FXCMCONTINUOUS_END)
{
_mapRequestsToAutoResetEvents[_currentRequest].Set();
_mapRequestsToAutoResetEvents.Remove(_currentRequest);
}
}
}
#endregion
#region IStatusMessageListener implementation
/// <summary>
/// Receives status messages from the FXCM API
/// </summary>
/// <param name="message">Status message received</param>
public void messageArrived(ISessionStatus message)
{
}
#endregion
/// <summary>
/// Aggregates a list of ticks at the requested resolution
/// </summary>
/// <param name="symbol"></param>
/// <param name="ticks"></param>
/// <param name="resolution"></param>
/// <returns></returns>
internal static IEnumerable<TradeBar> AggregateTicks(Symbol symbol, IEnumerable<Tick> ticks, TimeSpan resolution)
{
return
(from t in ticks
group t by t.Time.RoundDown(resolution)
into g
select new TradeBar
{
Symbol = symbol,
Time = g.Key,
Open = g.First().LastPrice,
High = g.Max(t => t.LastPrice),
Low = g.Min(t => t.LastPrice),
Close = g.Last().LastPrice
});
}
#region Console Helper
/// <summary>
/// Draw a progress bar
/// </summary>
/// <param name="complete"></param>
/// <param name="maxVal"></param>
/// <param name="barSize"></param>
/// <param name="progressCharacter"></param>
private static void progressBar(long complete, long maxVal, long barSize, char progressCharacter)
{
decimal p = (decimal)complete / (decimal)maxVal;
int chars = (int)Math.Floor(p / ((decimal)1 / (decimal)barSize));
string bar = string.Empty;
bar = bar.PadLeft(chars, progressCharacter);
bar = bar.PadRight(Convert.ToInt32(barSize)-1);
Console.Write($"\r[{bar}] {(p * 100).ToStringInvariant("N2")}%");
}
#endregion
}
}

View File

@@ -1,109 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using org.apache.log4j;
using QuantConnect.Configuration;
using QuantConnect.Data.Market;
using QuantConnect.Logging;
using QuantConnect.Util;
namespace QuantConnect.ToolBox.FxcmDownloader
{
public static class FxcmDownloaderProgram
{
/// <summary>
/// Primary entry point to the program
/// </summary>
public static void FxcmDownloader(IList<string> tickers, string resolution, DateTime startDate, DateTime endDate)
{
if (resolution.IsNullOrEmpty() || tickers.IsNullOrEmpty())
{
Console.WriteLine("FxcmDownloader ERROR: '--tickers=' or '--resolution=' parameter is missing");
Console.WriteLine("--tickers=eg EURUSD,USDJPY");
Console.WriteLine("--resolution=Second/Minute/Hour/Daily/All");
Environment.Exit(1);
}
try
{
Logger.getRootLogger().setLevel(Level.ERROR);
BasicConfigurator.configure(new FileAppender(new SimpleLayout(), "FxcmDownloader.log", append: false));
var allResolutions = resolution.ToLowerInvariant() == "all";
var castResolution = allResolutions ? Resolution.Tick : (Resolution)Enum.Parse(typeof(Resolution), resolution);
endDate = endDate.AddDays(1).AddMilliseconds(-1);
// Load settings from config.json
var dataDirectory = Config.Get("data-directory", "../../../Data");
var server = Config.Get("fxcm-server", "http://www.fxcorporate.com/Hosts.jsp");
var terminal = Config.Get("fxcm-terminal", "Demo");
var userName = Config.Get("fxcm-user-name", "username");
var password = Config.Get("fxcm-password", "password");
// Download the data
const string market = Market.FXCM;
var downloader = new FxcmDataDownloader(server, terminal, userName, password);
foreach (var ticker in tickers)
{
if (!downloader.HasSymbol(ticker))
throw new ArgumentException("The ticker " + ticker + " is not available.");
}
foreach (var ticker in tickers)
{
var securityType = downloader.GetSecurityType(ticker);
var symbol = Symbol.Create(ticker, securityType, market);
var data = downloader.Get(symbol, castResolution, startDate, endDate);
if (allResolutions)
{
var ticks = data.Cast<Tick>().ToList();
// Save the data (second resolution)
var writer = new LeanDataWriter(castResolution, symbol, dataDirectory);
writer.Write(ticks);
// Save the data (other resolutions)
foreach (var res in new[] { Resolution.Second, Resolution.Minute, Resolution.Hour, Resolution.Daily })
{
var resData = FxcmDataDownloader.AggregateTicks(symbol, ticks, res.ToTimeSpan());
writer = new LeanDataWriter(res, symbol, dataDirectory);
writer.Write(resData);
}
}
else
{
// Save the data (single resolution)
var writer = new LeanDataWriter(castResolution, symbol, dataDirectory);
writer.Write(data);
}
}
}
catch (Exception err)
{
Log.Error(err);
}
}
}
}

View File

@@ -1,90 +0,0 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Ionic.Zip;
using QuantConnect.Data.Custom;
namespace QuantConnect.ToolBox
{
public static class FxcmVolumeAuxiliaryMethods
{
public static IEnumerable<FxcmVolume> GetFxcmVolumeFromZip(string dataZipFile)
{
var output = new List<FxcmVolume>();
var data = ReadZipFileData(dataZipFile);
foreach (var obs in data)
{
var time = DateTime.ParseExact(obs[0], "yyyyMMdd HH:mm", CultureInfo.InvariantCulture);
output.Add(new FxcmVolume
{
DataType = MarketDataType.Base,
Time = time,
Value = Parse.Long(obs[1]),
Transactions = Parse.Int(obs[2])
});
}
return output;
}
public static List<string[]> ReadZipFolderData(string outputFolder)
{
var actualdata = new List<string[]>();
var files = Directory.GetFiles(outputFolder, "*.zip");
foreach (var file in files)
{
actualdata.AddRange(ReadZipFileData(file));
}
return actualdata;
}
public static List<string[]> ReadZipFileData(string dataZipFile)
{
var actualdata = new List<string[]>();
using (ZipFile zip = ZipFile.Read(dataZipFile))
using (var entryReader = new StreamReader(zip.First().OpenReader()))
{
while (!entryReader.EndOfStream)
{
actualdata.Add(entryReader.ReadLine().Split(','));
}
}
return actualdata;
}
public static DateTime? GetLastAvailableDateOfData(Symbol symbol, Resolution resolution, string folderPath)
{
if (!Directory.Exists(folderPath)) return null;
DateTime? lastAvailableDate = null;
switch (resolution)
{
case Resolution.Daily:
case Resolution.Hour:
var expectedFilePath = Path.Combine(folderPath, $"{symbol.Value.ToLowerInvariant()}_volume.zip"
);
if (File.Exists(expectedFilePath))
{
var lastStrDate = ReadZipFileData(expectedFilePath).Last() // last observation
.First() // first string (date)
.Substring(startIndex: 0, length: 8);
lastAvailableDate = DateTime.ParseExact(lastStrDate, DateFormat.EightCharacter, CultureInfo.InvariantCulture);
}
break;
case Resolution.Minute:
var lastFileDate = Directory
.GetFiles(folderPath, "*_volume.zip")
.OrderBy(f => f)
.LastOrDefault();
if (lastFileDate != null)
{
lastFileDate = Path.GetFileNameWithoutExtension(lastFileDate)
.Substring(startIndex: 0, length: 8);
lastAvailableDate = DateTime.ParseExact(lastFileDate, DateFormat.EightCharacter, CultureInfo.InvariantCulture);
}
break;
}
return lastAvailableDate;
}
}
}

View File

@@ -1,95 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Configuration;
using QuantConnect.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Util;
namespace QuantConnect.ToolBox.FxcmVolumeDownload
{
public static class FxcmVolumeDownloadProgram
{
public static void FxcmVolumeDownload(IList<string> tickers, string resolution, DateTime startDate, DateTime endDate)
{
var isUpdate = false;
if (resolution.IsNullOrEmpty())
{
if (!tickers.IsNullOrEmpty())
{
var _tickers = tickers.First().ToLowerInvariant();
if (_tickers == "all" || _tickers == "update")
{
if (_tickers == "update")
{
isUpdate = true;
}
tickers = new List<string> { "EURUSD","USDJPY","GBPUSD","USDCHF","EURCHF","AUDUSD","USDCAD",
"NZDUSD","EURGBP","EURJPY","GBPJPY","EURAUD","EURCAD","AUDJPY" };
resolution = "all";
}
}
else
{
Console.WriteLine("Usage:\n\t" +
"FxcmVolumeDownloader all\t will download data for all available pair for the three resolutions.\n\t" +
"FxcmVolumeDownloader update\t will download just last day data for all pair and resolutions already downloaded.");
Console.WriteLine("Usage: FxcmVolumeDownloader --tickers= --resolution= --from-date= --to-date=");
Console.WriteLine("--tickers=eg EURUSD,USDJPY\n" +
"\tAvailable pairs:\n" +
"\tEURUSD, USDJPY, GBPUSD, USDCHF, EURCHF, AUDUSD, USDCAD,\n" +
"\tNZDUSD, EURGBP, EURJPY, GBPJPY, EURAUD, EURCAD, AUDJPY");
Console.WriteLine("--resolution=Minute/Hour/Daily/All");
Environment.Exit(exitCode: 1);
}
}
try
{
Log.DebuggingEnabled = true;
Log.LogHandler = new CompositeLogHandler(new ConsoleLogHandler(), new FileLogHandler("FxcmFxVolumeDownloader.log", useTimestampPrefix: false));
var resolutions = new[] { Resolution.Daily };
if (resolution.ToLowerInvariant() == "all")
{
resolutions = new[] { Resolution.Daily, Resolution.Hour, Resolution.Minute };
}
else
{
resolutions[0] = (Resolution)Enum.Parse(typeof(Resolution), resolution);
}
// Load settings from config.json
var dataDirectory = Config.Get("data-directory", "../../../Data");
var downloader = new FxcmVolumeDownloader(dataDirectory);
foreach (var ticker in tickers)
{
var symbol = Symbol.Create(ticker, SecurityType.Base, Market.FXCM);
foreach (var _resolution in resolutions)
{
downloader.Run(symbol, _resolution, startDate, endDate, isUpdate);
}
}
}
catch (Exception err)
{
Log.Error(err);
}
}
}
}

View File

@@ -1,291 +0,0 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using QuantConnect.Data;
using QuantConnect.Data.Custom;
namespace QuantConnect.ToolBox
{
/// <summary>
/// FXCM Real FOREX Volume/Transactions Downloader Toolbox Project For LEAN Algorithmic Trading Engine.
/// </summary>
/// <seealso cref="QuantConnect.ToolBox.IDataDownloader" />
public class FxcmVolumeDownloader : IDataDownloader
{
private enum FxcmSymbolId
{
EURUSD = 1,
USDJPY = 2,
GBPUSD = 3,
USDCHF = 4,
EURCHF = 5,
AUDUSD = 6,
USDCAD = 7,
NZDUSD = 8,
EURGBP = 9,
EURJPY = 10,
GBPJPY = 11,
EURAUD = 14,
EURCAD = 15,
AUDJPY = 17
}
#region Fields
/// <summary>
/// The request base URL.
/// </summary>
private readonly string _baseUrl = " http://marketsummary2.fxcorporate.com/ssisa/servlet?RT=SSI";
private readonly string _dataDirectory;
/// <summary>
/// FXCM session id.
/// </summary>
private readonly string _sid = "quantconnect";
/// <summary>
/// The columns index which should be added to obtain the transactions.
/// </summary>
private readonly long[] _transactionsIdx = {27, 29, 31, 33};
/// <summary>
/// Integer representing client version.
/// </summary>
private readonly int _ver = 1;
/// <summary>
/// The columns index which should be added to obtain the volume.
/// </summary>
private readonly int[] _volumeIdx = {26, 28, 30, 32};
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="FxcmVolumeDownloader" /> class.
/// </summary>
/// <param name="dataDirectory">The Lean data directory.</param>
public FxcmVolumeDownloader(string dataDirectory)
{
_dataDirectory = dataDirectory;
}
#region Public Methods
/// <summary>
/// Get historical data enumerable for a single symbol, type and resolution given this start and end time (in UTC).
/// </summary>
/// <param name="symbol">Symbol for the data we're looking for.</param>
/// <param name="resolution">Resolution of the data request</param>
/// <param name="startUtc">Start time of the data in UTC</param>
/// <param name="endUtc">End time of the data in UTC</param>
/// <returns>
/// Enumerable of base data for this symbol
/// </returns>
public IEnumerable<BaseData> Get(Symbol symbol, Resolution resolution, DateTime startUtc, DateTime endUtc)
{
var idx = 0;
var obsTime = startUtc;
var requestedData = new List<BaseData>();
var lines = RequestData(symbol, resolution, startUtc, endUtc);
do
{
var line = lines[idx++];
var obs = line.Split(';');
var stringDate = obs[0].Substring(startIndex: 3);
obsTime = DateTime.ParseExact(stringDate, "yyyyMMddHHmm",
DateTimeFormatInfo.InvariantInfo);
var volume = _volumeIdx.Select(x => Parse.Long(obs[x])).Sum();
var transactions = _transactionsIdx.Select(x => Parse.Int(obs[x])).Sum();
requestedData.Add(new FxcmVolume
{
Symbol = symbol,
Time = obsTime,
Value = volume,
Transactions = transactions
});
} while (obsTime.Date <= endUtc.Date && idx < lines.Length - 1);
return requestedData.Where(o => o.Time.Date >= startUtc.Date && o.Time.Date <= endUtc.Date);
}
/// <summary>
/// Method in charge of making all the steps to save the data. It makes the request, parses the data and saves it.
/// This method takes into account the size limitation of the responses, slicing big request into smaller ones.
/// </summary>
/// <param name="symbol">The symbol.</param>
/// <param name="resolution">The resolution.</param>
/// <param name="startUtc">The start UTC.</param>
/// <param name="endUtc">The end UTC.</param>
/// <param name="update">Flag to </param>
public void Run(Symbol symbol, Resolution resolution, DateTime startUtc, DateTime endUtc, bool update = false)
{
var data = new List<BaseData>();
var requestDayInterval = 0;
var writer = new FxcmVolumeWriter(resolution, symbol, _dataDirectory);
var intermediateStartDate = startUtc;
var intermediateEndDate = endUtc;
if (update)
{
var updatedStartDate = FxcmVolumeAuxiliaryMethods.GetLastAvailableDateOfData(symbol, resolution, writer.FolderPath);
if (updatedStartDate == null) return;
intermediateStartDate = ((DateTime) updatedStartDate).AddDays(value: -1);
intermediateEndDate = DateTime.Today;
}
// As the responses has a Limit of 10000 lines, hourly data the minute data request should be sliced.
if (resolution == Resolution.Minute && (endUtc - startUtc).TotalMinutes > 10000)
{
// Six days are 8640 minute observations, 7 days are 10080.
requestDayInterval = 6;
}
else if (resolution == Resolution.Hour && (endUtc - startUtc).TotalHours > 10000)
{
// 410 days x 24 hr = 9840 hr.
requestDayInterval = 410;
}
var counter = 0;
do
{
if (requestDayInterval != 0)
{
if (counter++ != 0)
{
intermediateStartDate = intermediateEndDate.AddDays(value: 1);
}
intermediateEndDate = intermediateStartDate.AddDays(requestDayInterval);
if (intermediateEndDate > endUtc) intermediateEndDate = endUtc;
}
data.AddRange(Get(symbol, resolution, intermediateStartDate, intermediateEndDate));
// For every 300k observations in memory, write it.
if (resolution == Resolution.Minute && counter % 30 == 0)
{
writer.Write(data);
data.Clear();
}
} while (intermediateEndDate != endUtc);
writer.Write(data, update);
}
#endregion
#region Private Methods
/// <summary>
/// Gets the FXCM identifier from a FOREX pair symbol.
/// </summary>
/// <param name="symbol">The pair symbol.</param>
/// <returns></returns>
/// <exception cref="System.ArgumentException">Volume data is not available for the selected symbol. - symbol</exception>
private int GetFxcmIDFromSymbol(Symbol symbol)
{
int symbolId;
try
{
symbolId = (int) Enum.Parse(typeof(FxcmSymbolId), symbol.Value);
}
catch (ArgumentException)
{
throw new ArgumentException("Volume data is not available for the selected symbol.", "symbol");
}
return symbolId;
}
/// <summary>
/// Gets the string interval representation from the resolution.
/// </summary>
/// <param name="resolution">The requested resolution.</param>
/// <returns></returns>
/// <exception cref="System.ArgumentOutOfRangeException">
/// resolution - tick or second resolution are not supported for Forex
/// Volume.
/// </exception>
private string GetIntervalFromResolution(Resolution resolution)
{
string interval;
switch (resolution)
{
case Resolution.Minute:
interval = "M1";
break;
case Resolution.Hour:
interval = "H1";
break;
case Resolution.Daily:
interval = "D1";
break;
default:
throw new ArgumentOutOfRangeException(nameof(resolution), resolution,
"tick or second resolution are not supported for Forex Volume.");
}
return interval;
}
/// <summary>
/// Generates the API Requests.
/// </summary>
/// <param name="symbol">The symbol.</param>
/// <param name="resolution">The resolution.</param>
/// <param name="startUtc">The start date in UTC.</param>
/// <param name="endUtc">The end date in UTC.</param>
/// <returns></returns>
private string[] RequestData(Symbol symbol, Resolution resolution, DateTime startUtc, DateTime endUtc)
{
var startDate = string.Empty;
var endDate = endUtc.AddDays(value: 2).ToStringInvariant("yyyyMMdd") + "2100";
var symbolId = GetFxcmIDFromSymbol(symbol);
var interval = GetIntervalFromResolution(resolution);
switch (resolution)
{
case Resolution.Minute:
case Resolution.Hour:
startDate = startUtc.ToStringInvariant("yyyyMMdd") + "0000";
break;
case Resolution.Daily:
startDate = startUtc.AddDays(value: 1).ToStringInvariant("yyyyMMdd") + "2100";
break;
}
var request = $"{_baseUrl}&ver={_ver}&sid={_sid}&interval={interval}&offerID={symbolId}" +
$"&timeFrom={startDate.ToStringInvariant()}&timeTo={endDate.ToStringInvariant()}";
string[] lines;
using (var client = new WebClient())
{
var data = client.DownloadString(request);
lines = data.Split('\n');
}
// Removes the HTML head and tail.
return lines.Skip(count: 2).Take(lines.Length - 4).ToArray();
}
#endregion
}
}

View File

@@ -1,107 +0,0 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using QuantConnect.Data;
using QuantConnect.Data.Custom;
namespace QuantConnect.ToolBox
{
public class FxcmVolumeWriter
{
#region Fields
private readonly Resolution _resolution;
private readonly Symbol _symbol;
#endregion
public string FolderPath { get; }
public FxcmVolumeWriter(Resolution resolution, Symbol symbol, string dataDirectory)
{
_symbol = symbol;
_resolution = resolution;
var market = _symbol.ID.Market;
FolderPath =
Path.Combine(new[] {dataDirectory, "forex", market.ToLowerInvariant(), _resolution.ToLower()});
if (_resolution == Resolution.Minute)
{
FolderPath = Path.Combine(FolderPath, _symbol.Value.ToLowerInvariant());
}
}
public void Write(IEnumerable<BaseData> data, bool update = false)
{
if (!Directory.Exists(FolderPath)) Directory.CreateDirectory(FolderPath);
if (update && _resolution != Resolution.Minute)
{
data = ReadActualDataAndAppendNewData(data);
}
// Seems the data has some duplicate values! This makes the writer throws an error. So, just in case, we clean the data from duplicates.
data = data.GroupBy(x => x.Time)
.Select(g => g.First());
if (_resolution == Resolution.Minute)
{
WriteMinuteData(data);
}
else
{
WriteHourAndDailyData(data);
}
}
#region Private Methods
private IEnumerable<BaseData> ReadActualDataAndAppendNewData(IEnumerable<BaseData> data)
{
// Read the actual data
var zipFilePath = Path.Combine(FolderPath, _symbol.Value.ToLowerInvariant() + "_volume.zip");
var actualData = FxcmVolumeAuxiliaryMethods.GetFxcmVolumeFromZip(zipFilePath);
return actualData.Concat(data);
}
private void WriteHourAndDailyData(IEnumerable<BaseData> data)
{
var sb = new StringBuilder();
var volData = data.Cast<FxcmVolume>();
foreach (var obs in volData)
{
sb.AppendLine($"{obs.Time.ToStringInvariant("yyyyMMdd HH:mm")},{obs.Value.ToStringInvariant()},{obs.Transactions}");
}
var data_to_save = sb.ToString();
var filename = _symbol.Value.ToLowerInvariant() + "_volume";
var csvFilePath = Path.Combine(FolderPath, filename + ".csv");
var zipFilePath = csvFilePath.Replace(".csv", ".zip");
if (File.Exists(zipFilePath)) File.Delete(zipFilePath);
File.WriteAllText(csvFilePath, data_to_save);
// Write out this data string to a zip file
Compression.Zip(csvFilePath, Path.GetFileName(csvFilePath));
}
private void WriteMinuteData(IEnumerable<BaseData> data)
{
var sb = new StringBuilder();
var volData = data.Cast<FxcmVolume>();
var dataByDay = volData.GroupBy(o => o.Time.Date);
foreach (var dayOfData in dataByDay)
{
foreach (var obs in dayOfData)
{
sb.AppendLine($"{obs.Time.TimeOfDay.TotalMilliseconds.ToStringInvariant()},{obs.Value.ToStringInvariant()},{obs.Transactions}");
}
var filename = $"{dayOfData.Key.ToStringInvariant("yyyyMMdd")}_volume.csv";
var filePath = Path.Combine(FolderPath, filename);
File.WriteAllText(filePath, sb.ToString());
// Write out this data string to a zip file
Compression.Zip(filePath, filename);
sb.Clear();
}
}
#endregion
}
}

View File

@@ -15,10 +15,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Market;
using QuantConnect.Util;
namespace QuantConnect.ToolBox
{

View File

@@ -15,7 +15,6 @@
*/
using System.Diagnostics;
using Microsoft.Win32;
using System.Threading;
using QuantConnect.Configuration;
@@ -41,29 +40,6 @@ namespace QuantConnect.ToolBox.IQFeed
);
}
public string getPath()
{
var key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\DTN\\IQFeed");
if (key == null)
{
// if it isn't in that location, it is possible the user is running and x64 OS. Check the windows virtualized registry location
key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Wow6432Node\\DTN\\IQFeed");
}
string sLocation = null;
if (key != null)
{
sLocation = key.GetValue("EXEDIR", "").ToString();
// close the key since we don't need it anymore
key.Close();
// verify there is a \ on the end before we append the exe name
if (!(sLocation.EndsWith("\\") || sLocation.EndsWith("/")))
{
sLocation += "\\";
}
sLocation += "IQConnect.exe";
}
return sLocation;
}
public string getArguments(IQCredentials iqc)
{
var arguments = "";

View File

@@ -19,7 +19,6 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using ikvm.extensions;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Util;
@@ -133,7 +132,7 @@ namespace QuantConnect.ToolBox.IVolatilityEquityConverter
private static Symbol GetSymbol(string fileName)
{
var splits = fileName.Split('_');
var ticker = splits[1].toLowerCase();
var ticker = splits[1].ToLowerInvariant();
return Symbol.Create(ticker, SecurityType.Equity, Market.USA);
}
@@ -144,7 +143,7 @@ namespace QuantConnect.ToolBox.IVolatilityEquityConverter
/// <returns></returns>
private static Resolution ParseResolution(string entry)
{
switch (entry.Trim().toLowerCase())
switch (entry.Trim().ToLowerInvariant())
{
case "minute":
return Resolution.Minute;

View File

@@ -14,8 +14,8 @@
*/
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Util;
namespace QuantConnect.ToolBox
{

View File

@@ -28,8 +28,6 @@ using QuantConnect.ToolBox.CoinApiDataConverter;
using QuantConnect.ToolBox.CryptoiqDownloader;
using QuantConnect.ToolBox.DukascopyDownloader;
using QuantConnect.ToolBox.EstimizeDataDownloader;
using QuantConnect.ToolBox.FxcmDownloader;
using QuantConnect.ToolBox.FxcmVolumeDownload;
using QuantConnect.ToolBox.GDAXDownloader;
using QuantConnect.ToolBox.IBDownloader;
using QuantConnect.ToolBox.IEX;
@@ -96,14 +94,6 @@ namespace QuantConnect.ToolBox
case "dukascopydownloader":
DukascopyDownloaderProgram.DukascopyDownloader(tickers, resolution, fromDate, toDate);
break;
case "fdl":
case "fxcmdownloader":
FxcmDownloaderProgram.FxcmDownloader(tickers, resolution, fromDate, toDate);
break;
case "fvdl":
case "fxcmvolumedownload":
FxcmVolumeDownloadProgram.FxcmVolumeDownload(tickers, resolution, fromDate, toDate);
break;
case "ibdl":
case "ibdownloader":
IBDownloaderProgram.IBDownloader(tickers, resolution, fromDate, toDate);

View File

@@ -5,7 +5,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>QuantConnect.ToolBox</RootNamespace>
<AssemblyName>QuantConnect.ToolBox</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>6</LangVersion>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
@@ -57,7 +57,6 @@
<PackageReference Include="Common.Logging" Version="3.4.1" />
<PackageReference Include="Common.Logging.Core" Version="3.4.1" />
<PackageReference Include="DotNetZip" Version="1.13.3" />
<PackageReference Include="IKVM" Version="8.1.5717.0" />
<PackageReference Include="IQFeed.CSharpApiClient" Version="2.5.1" />
<PackageReference Include="LaunchDarkly.EventSource" Version="3.3.2" />
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.6.0" />
@@ -99,16 +98,6 @@
<PackageReference Include="Utf8Json" Version="1.3.7" />
<PackageReference Include="WebSocket4Net" Version="0.15.2" />
</ItemGroup>
<ItemGroup>
<Reference Include="QuantConnect.Fxcm">
<HintPath>..\Brokerages\Fxcm\QuantConnect.Fxcm.dll</HintPath>
</Reference>
<Reference Include="System.Configuration" />
<Reference Include="System.Net" />
<Reference Include="System.Web" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<None Include="..\LICENSE">
<Pack>True</Pack>