├── .gitattributes ├── .gitignore ├── Backlog.md ├── CSharp ├── .gitignore ├── .nuget │ ├── NuGet.Config │ ├── NuGet.exe │ └── NuGet.targets ├── OtherTeam.StandardizedMarketGatewayAPI │ ├── ApiDealExecutedEventArgs.cs │ ├── ApiLimitOrder.cs │ ├── ApiMarketDataUpdateEventArgs.cs │ ├── ApiMarketGateway.cs │ ├── ApiMarketOrder.cs │ ├── ApiMarketWay.cs │ ├── ApiOrder.cs │ ├── ApiOrderFailedEventArgs.cs │ ├── OtherTeam.StandardizedMarketGatewayAPI.csproj │ └── Properties │ │ └── AssemblyInfo.cs ├── Settings.StyleCop ├── SimpleOrderRouting.Console │ ├── App.config │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── SimpleOrderRouting.Console.csproj ├── SimpleOrderRouting.Domain │ ├── ICanReceiveMarketData.cs │ ├── ICanRouteOrders.cs │ ├── IHandleInvestorInstructions.cs │ ├── IOrder.cs │ ├── IProvideMarkets.cs │ ├── ISolveInvestorInstructions.cs │ ├── InvestorIntructionCallback.cs │ ├── Investors │ │ ├── InstructionExecutionContext.cs │ │ ├── InvestorInstruction.cs │ │ ├── InvestorInstructionExecutedEventArgs.cs │ │ └── InvestorInstructionStatus.cs │ ├── Markets │ │ ├── Feeds │ │ │ └── MarketDataUpdatedArgs.cs │ │ ├── MarketInfo.cs │ │ ├── MarketSnapshot.cs │ │ ├── MarketSnapshotProvider.cs │ │ └── Orders │ │ │ ├── DealExecutedEventArgs.cs │ │ │ ├── InstrumentIdentifier.cs │ │ │ ├── OrderBasket.cs │ │ │ ├── OrderDescription.cs │ │ │ ├── OrderExecutedEventArgs.cs │ │ │ └── OrderFailedEventArgs.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── SimpleOrderRouting.Domain.csproj │ ├── SmartOrderRoutingEngine.cs │ ├── SolvingStrategies │ │ └── MarketSweepSolver.cs │ └── Way.cs ├── SimpleOrderRouting.Infra │ ├── CompositionRootHelper.cs │ ├── Investors │ │ ├── InstructionExecutedDto.cs │ │ ├── InstructionFailedDto.cs │ │ ├── InvestorInstructionDto.cs │ │ ├── InvestorInstructionDtoCallBacks.cs │ │ ├── InvestorInstructionIdentifierDto.cs │ │ ├── InvestorInstructionUpdatedDto.cs │ │ ├── InvestorInstructionsAdapter.cs │ │ └── Way.cs │ ├── Markets │ │ ├── LimitOrderAdapter.cs │ │ ├── MarketDataAdapter.cs │ │ ├── MarketOrderAdapter.cs │ │ ├── MarketsAdapter.cs │ │ ├── OrderAdapter.cs │ │ └── OrderRoutingAdapter.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Settings.StyleCop │ ├── SimpleOrderRouting.Infra.csproj │ └── SimpleOrderRouting.Infra.csproj.DotSettings ├── SimpleOrderRouting.Tests │ ├── Infra │ │ ├── ApiMarketGatewayTests.cs │ │ ├── HarnessTests.cs │ │ ├── InvestorInstructionDtoTests.cs │ │ └── SorTestHarness.cs │ ├── InvestorInstructionTests.cs │ ├── MarketSweepSolverTests.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Settings.StyleCop │ ├── SimpleOrderRouting.Tests.csproj │ ├── SorAcceptanceTests.cs │ └── packages.config ├── SimpleOrderRouting.sln └── SimpleOrderRouting.sln.DotSettings ├── DoD.md ├── FSharp ├── SimpleOrderRouting.Journey1 │ ├── Adapters.fs │ ├── Adapters.fsi │ ├── Domain.fs │ ├── Domain.fsi │ ├── External.fs │ ├── External.fsi │ ├── MarketDataAdapter.fs │ ├── Ports.fs │ ├── SORoutingEngine.fs │ ├── Script.fsx │ ├── SimpleOrderRouting.Journey1.fsproj │ └── Utilities.fs ├── SimpleOrderRouting.Tests │ ├── MarketTests.fs │ ├── SimpleOrderRouting.Tests.fsproj │ ├── SorAcceptanceTests.fs │ ├── UtilitiesTests.fs │ ├── app.config │ └── packages.config └── SimpleOrderRouting.sln ├── LICENSE.txt ├── Readme.md └── images ├── 10kfeet.jpg ├── 25kfeet.jpg ├── 5feet.jpg ├── Hegagonal-firstDraft.jpg ├── HexaMendel.jpg ├── HexaThomas.jpg ├── HexaTomasz.jpg ├── MarketsRaceConditions.jpg ├── PortAndAdapters.jpg ├── SOR-bigPicture.jpg ├── XPDesign.jpg ├── You-Are-Here.jpg ├── duty_calls.png └── goodmanpistoff.jpg /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | [Bb]in/ 16 | [Oo]bj/ 17 | 18 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 19 | !packages/*/build/ 20 | 21 | # MSTest test Results 22 | [Tt]est[Rr]esult*/ 23 | [Bb]uild[Ll]og.* 24 | 25 | *_i.c 26 | *_p.c 27 | *.ilk 28 | *.meta 29 | *.obj 30 | *.pch 31 | *.pdb 32 | *.pgc 33 | *.pgd 34 | *.rsp 35 | *.sbr 36 | *.tlb 37 | *.tli 38 | *.tlh 39 | *.tmp 40 | *.tmp_proj 41 | *.log 42 | *.vspscc 43 | *.vssscc 44 | .builds 45 | *.pidb 46 | *.log 47 | *.scc 48 | 49 | # Visual C++ cache files 50 | ipch/ 51 | *.aps 52 | *.ncb 53 | *.opensdf 54 | *.sdf 55 | *.cachefile 56 | 57 | # Visual Studio profiler 58 | *.psess 59 | *.vsp 60 | *.vspx 61 | 62 | # Guidance Automation Toolkit 63 | *.gpState 64 | 65 | # ReSharper is a .NET coding add-in 66 | _ReSharper*/ 67 | *.[Rr]e[Ss]harper 68 | 69 | # TeamCity is a build add-in 70 | _TeamCity* 71 | 72 | # DotCover is a Code Coverage Tool 73 | *.dotCover 74 | 75 | # NCrunch 76 | *.ncrunch* 77 | .*crunch*.local.xml 78 | 79 | # Installshield output folder 80 | [Ee]xpress/ 81 | 82 | # DocProject is a documentation generator add-in 83 | DocProject/buildhelp/ 84 | DocProject/Help/*.HxT 85 | DocProject/Help/*.HxC 86 | DocProject/Help/*.hhc 87 | DocProject/Help/*.hhk 88 | DocProject/Help/*.hhp 89 | DocProject/Help/Html2 90 | DocProject/Help/html 91 | 92 | # Click-Once directory 93 | publish/ 94 | 95 | # Publish Web Output 96 | *.Publish.xml 97 | 98 | # NuGet Packages Directory 99 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 100 | packages/ 101 | 102 | # Windows Azure Build Output 103 | csx 104 | *.build.csdef 105 | 106 | # Windows Store app package directory 107 | AppPackages/ 108 | 109 | # Others 110 | sql/ 111 | *.Cache 112 | ClientBin/ 113 | [Ss]tyle[Cc]op.* 114 | ~$* 115 | *~ 116 | *.dbmdl 117 | *.[Pp]ublish.xml 118 | *.pfx 119 | *.publishsettings 120 | 121 | # RIA/Silverlight projects 122 | Generated_Code/ 123 | 124 | # Backup & report files from converting an old project file to a newer 125 | # Visual Studio version. Backup files are not needed, because we have git ;-) 126 | _UpgradeReport_Files/ 127 | Backup*/ 128 | UpgradeLog*.XML 129 | UpgradeLog*.htm 130 | 131 | # SQL Server files 132 | App_Data/*.mdf 133 | App_Data/*.ldf 134 | 135 | 136 | #LightSwitch generated files 137 | GeneratedArtifacts/ 138 | _Pvt_Extensions/ 139 | ModelManifest.xml 140 | 141 | # ========================= 142 | # Windows detritus 143 | # ========================= 144 | 145 | # Windows image file caches 146 | Thumbs.db 147 | ehthumbs.db 148 | 149 | # Folder config file 150 | Desktop.ini 151 | 152 | # Recycle Bin used on file shares 153 | $RECYCLE.BIN/ 154 | 155 | # Mac desktop service store files 156 | .DS_Store 157 | -------------------------------------------------------------------------------- /Backlog.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/Backlog.md -------------------------------------------------------------------------------- /CSharp/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # MSTest test Results 20 | [Tt]est[Rr]esult*/ 21 | [Bb]uild[Ll]og.* 22 | 23 | #NUNIT 24 | *.VisualState.xml 25 | TestResult.xml 26 | 27 | # Build Results of an ATL Project 28 | [Dd]ebugPS/ 29 | [Rr]eleasePS/ 30 | dlldata.c 31 | 32 | *_i.c 33 | *_p.c 34 | *_i.h 35 | *.ilk 36 | *.meta 37 | *.obj 38 | *.pch 39 | *.pdb 40 | *.pgc 41 | *.pgd 42 | *.rsp 43 | *.sbr 44 | *.tlb 45 | *.tli 46 | *.tlh 47 | *.tmp 48 | *.tmp_proj 49 | *.log 50 | *.vspscc 51 | *.vssscc 52 | .builds 53 | *.pidb 54 | *.svclog 55 | *.scc 56 | 57 | # Chutzpah Test files 58 | _Chutzpah* 59 | 60 | # Visual C++ cache files 61 | ipch/ 62 | *.aps 63 | *.ncb 64 | *.opensdf 65 | *.sdf 66 | *.cachefile 67 | 68 | # Visual Studio profiler 69 | *.psess 70 | *.vsp 71 | *.vspx 72 | 73 | # TFS 2012 Local Workspace 74 | $tf/ 75 | 76 | # Guidance Automation Toolkit 77 | *.gpState 78 | 79 | # ReSharper is a .NET coding add-in 80 | _ReSharper*/ 81 | *.[Rr]e[Ss]harper 82 | *.DotSettings.user 83 | 84 | # JustCode is a .NET coding addin-in 85 | .JustCode 86 | 87 | # TeamCity is a build add-in 88 | _TeamCity* 89 | 90 | # DotCover is a Code Coverage Tool 91 | *.dotCover 92 | 93 | # NCrunch 94 | *.ncrunch* 95 | _NCrunch_* 96 | .*crunch*.local.xml 97 | 98 | # MightyMoose 99 | *.mm.* 100 | AutoTest.Net/ 101 | 102 | # Web workbench (sass) 103 | .sass-cache/ 104 | 105 | # Installshield output folder 106 | [Ee]xpress/ 107 | 108 | # DocProject is a documentation generator add-in 109 | DocProject/buildhelp/ 110 | DocProject/Help/*.HxT 111 | DocProject/Help/*.HxC 112 | DocProject/Help/*.hhc 113 | DocProject/Help/*.hhk 114 | DocProject/Help/*.hhp 115 | DocProject/Help/Html2 116 | DocProject/Help/html 117 | 118 | # Click-Once directory 119 | publish/ 120 | 121 | # Publish Web Output 122 | *.[Pp]ublish.xml 123 | *.azurePubxml 124 | 125 | # NuGet Packages Directory 126 | packages/ 127 | ## TODO: If the tool you use requires repositories.config uncomment the next line 128 | #!packages/repositories.config 129 | 130 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 131 | # This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) 132 | !packages/build/ 133 | 134 | # Windows Azure Build Output 135 | csx/ 136 | *.build.csdef 137 | 138 | # Windows Store app package directory 139 | AppPackages/ 140 | 141 | # Others 142 | sql/ 143 | *.Cache 144 | ClientBin/ 145 | [Ss]tyle[Cc]op.* 146 | ~$* 147 | *~ 148 | *.dbmdl 149 | *.dbproj.schemaview 150 | *.pfx 151 | *.publishsettings 152 | node_modules/ 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | *.mdf 166 | *.ldf 167 | 168 | # Business Intelligence projects 169 | *.rdl.data 170 | *.bim.layout 171 | *.bim_*.settings 172 | 173 | # Microsoft Fakes 174 | FakesAssemblies/ 175 | -------------------------------------------------------------------------------- /CSharp/.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CSharp/.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/CSharp/.nuget/NuGet.exe -------------------------------------------------------------------------------- /CSharp/.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 12 | 13 | true 14 | 15 | 16 | false 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 31 | 32 | 33 | 34 | 35 | $(SolutionDir).nuget 36 | 37 | 38 | 39 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config 40 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config 41 | 42 | 43 | 44 | $(MSBuildProjectDirectory)\packages.config 45 | $(PackagesProjectConfig) 46 | 47 | 48 | 49 | 50 | $(NuGetToolsPath)\NuGet.exe 51 | @(PackageSource) 52 | 53 | "$(NuGetExePath)" 54 | mono --runtime=v4.0.30319 "$(NuGetExePath)" 55 | 56 | $(TargetDir.Trim('\\')) 57 | 58 | -RequireConsent 59 | -NonInteractive 60 | 61 | "$(SolutionDir) " 62 | "$(SolutionDir)" 63 | 64 | 65 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) 66 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols 67 | 68 | 69 | 70 | RestorePackages; 71 | $(BuildDependsOn); 72 | 73 | 74 | 75 | 76 | $(BuildDependsOn); 77 | BuildPackage; 78 | 79 | 80 | 81 | 82 | 83 | 84 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 99 | 100 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /CSharp/OtherTeam.StandardizedMarketGatewayAPI/ApiDealExecutedEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace OtherTeam.StandardizedMarketGatewayAPI 2 | { 3 | using System; 4 | 5 | /// 6 | /// Event data for DealExecuted event. 7 | /// 8 | public class ApiDealExecutedEventArgs : EventArgs 9 | { 10 | public ApiDealExecutedEventArgs(decimal price, int quantity) 11 | { 12 | this.Price = price; 13 | this.Quantity = quantity; 14 | } 15 | 16 | public decimal Price { get; private set; } 17 | 18 | public int Quantity { get; private set; } 19 | } 20 | } -------------------------------------------------------------------------------- /CSharp/OtherTeam.StandardizedMarketGatewayAPI/ApiLimitOrder.cs: -------------------------------------------------------------------------------- 1 | namespace OtherTeam.StandardizedMarketGatewayAPI 2 | { 3 | public class ApiLimitOrder : ApiOrder 4 | { 5 | public decimal Price { get; private set; } 6 | 7 | public ApiLimitOrder(ApiMarketWay way, int quantity, decimal price, bool allowPartialExecution) 8 | { 9 | this.Quantity = quantity; 10 | this.Price = price; 11 | this.AllowPartialExecution = allowPartialExecution; 12 | this.Way = way; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /CSharp/OtherTeam.StandardizedMarketGatewayAPI/ApiMarketDataUpdateEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace OtherTeam.StandardizedMarketGatewayAPI 2 | { 3 | using System; 4 | 5 | public class ApiMarketDataUpdateEventArgs : EventArgs 6 | { 7 | public ApiMarketDataUpdateEventArgs(string originMarketName, decimal marketPrice, int quantityOnTheMarket) 8 | { 9 | this.QuantityOnTheMarket = quantityOnTheMarket; 10 | this.MarketPrice = marketPrice; 11 | this.OriginMarketName = originMarketName; 12 | } 13 | 14 | // TODO : introduce the concept of various instruments 15 | 16 | public string OriginMarketName { get; private set; } 17 | public decimal MarketPrice { get; private set; } 18 | public int QuantityOnTheMarket { get; private set; } 19 | } 20 | } -------------------------------------------------------------------------------- /CSharp/OtherTeam.StandardizedMarketGatewayAPI/ApiMarketGateway.cs: -------------------------------------------------------------------------------- 1 | namespace OtherTeam.StandardizedMarketGatewayAPI 2 | { 3 | using System; 4 | 5 | /// 6 | /// Gives access and mocks a Market given various initialization informations. 7 | /// 8 | public class ApiMarketGateway 9 | { 10 | public ApiMarketGateway(string marketName, int sellQuantity, decimal sellPrice, Predicate orderPredicate = null) 11 | { 12 | this.MarketName = marketName; 13 | this.SellQuantity = sellQuantity; 14 | this.SellPrice = sellPrice; 15 | this.OrderPredicate = orderPredicate; 16 | } 17 | 18 | public event EventHandler MarketDataUpdated; 19 | 20 | public event EventHandler OrderExecuted; 21 | 22 | // TODO: set a proper event handler instead of this string 23 | public event EventHandler OrderFailed; 24 | 25 | public string MarketName { get; private set; } 26 | 27 | public int SellQuantity { get; private set; } 28 | 29 | public decimal SellPrice { get; private set; } 30 | 31 | public int TimesSent { get; private set; } 32 | 33 | public Predicate OrderPredicate { get; set; } 34 | 35 | public ApiMarketOrder CreateMarketOrder(ApiMarketWay way, int quantity) 36 | { 37 | return new ApiMarketOrder(way, quantity); 38 | } 39 | 40 | public ApiLimitOrder CreateLimitOrder(ApiMarketWay apiMarketWay, int quantity, decimal price, bool allowPartial) 41 | { 42 | return new ApiLimitOrder(apiMarketWay, quantity, price, allowPartial); 43 | } 44 | 45 | public void Send(ApiMarketOrder marketOrder) 46 | { 47 | this.TimesSent++; 48 | 49 | if (this.PredicateFailed(marketOrder)) 50 | { 51 | this.RaiseOrderFailed(marketOrder, new ApiOrderFailedEventArgs(this.MarketName, "Predicate failed.")); 52 | return; 53 | } 54 | 55 | switch (marketOrder.Way) 56 | { 57 | case ApiMarketWay.Buy: 58 | if (this.AskMoreThanAvailableQuantityAndDontSupportPartialExecution(marketOrder)) 59 | { 60 | this.RaiseOrderFailed(marketOrder, new ApiOrderFailedEventArgs(this.MarketName, "Excessive quantity!")); 61 | return; 62 | } 63 | 64 | this.ExecuteProperQuantity(marketOrder); 65 | 66 | break; 67 | 68 | default: 69 | throw new NotImplementedException(); 70 | break; 71 | } 72 | } 73 | 74 | private void ExecuteProperQuantity(ApiOrder marketOrder) 75 | { 76 | var executedQuantity = Math.Min(marketOrder.Quantity, this.SellQuantity); 77 | this.SellQuantity -= executedQuantity; 78 | 79 | this.RaiseMarketDataUpdated(this.SellPrice, this.SellQuantity); 80 | this.RaiseOrderExecuted(marketOrder, executedQuantity); 81 | } 82 | 83 | private bool PredicateFailed(ApiOrder marketOrder) 84 | { 85 | return this.OrderPredicate != null && this.OrderPredicate(marketOrder) == false; 86 | } 87 | 88 | public void Send(ApiLimitOrder limitOrder) 89 | { 90 | this.TimesSent++; 91 | 92 | if (this.PredicateFailed(limitOrder)) 93 | { 94 | this.RaiseOrderFailed(limitOrder, new ApiOrderFailedEventArgs(this.MarketName, "Predicate failed.")); 95 | return; 96 | } 97 | 98 | switch (limitOrder.Way) 99 | { 100 | case ApiMarketWay.Buy: 101 | if (limitOrder.Price > this.SellPrice) 102 | { 103 | this.RaiseOrderFailed(limitOrder, new ApiOrderFailedEventArgs(this.MarketName, "Invalid price")); 104 | return; 105 | } 106 | 107 | if (this.AskMoreThanAvailableQuantityAndDontSupportPartialExecution(limitOrder)) 108 | { 109 | this.RaiseOrderFailed(limitOrder, new ApiOrderFailedEventArgs(this.MarketName, "Excessive quantity!")); 110 | return; 111 | } 112 | 113 | this.ExecuteProperQuantity(limitOrder); 114 | 115 | break; 116 | 117 | default: 118 | throw new NotImplementedException(); 119 | break; 120 | } 121 | } 122 | 123 | private bool AskMoreThanAvailableQuantityAndDontSupportPartialExecution(ApiOrder limitOrder) 124 | { 125 | return (limitOrder.Quantity > this.SellQuantity) && (!limitOrder.AllowPartialExecution); 126 | } 127 | 128 | private void RaiseMarketDataUpdated(decimal newSellPrice, int newQuantityOnTheMarket) 129 | { 130 | var marketDataUpdated = this.MarketDataUpdated; 131 | if (marketDataUpdated != null) 132 | { 133 | marketDataUpdated(this, new ApiMarketDataUpdateEventArgs(this.MarketName, newSellPrice, newQuantityOnTheMarket)); 134 | } 135 | } 136 | 137 | private void RaiseOrderExecuted(ApiOrder order, int executedQuantity) 138 | { 139 | var onOrderExecuted = this.OrderExecuted; 140 | if (onOrderExecuted != null) 141 | { 142 | onOrderExecuted(order, new ApiDealExecutedEventArgs(this.SellPrice, executedQuantity)); 143 | } 144 | } 145 | 146 | private void RaiseOrderFailed(ApiOrder order, ApiOrderFailedEventArgs args) 147 | { 148 | var onOrderFailed = this.OrderFailed; 149 | if (onOrderFailed != null) 150 | { 151 | onOrderFailed(order, args); 152 | } 153 | } 154 | 155 | 156 | } 157 | } -------------------------------------------------------------------------------- /CSharp/OtherTeam.StandardizedMarketGatewayAPI/ApiMarketOrder.cs: -------------------------------------------------------------------------------- 1 | namespace OtherTeam.StandardizedMarketGatewayAPI 2 | { 3 | public class ApiMarketOrder : ApiOrder 4 | { 5 | public new bool AllowPartialExecution 6 | { 7 | get 8 | { 9 | return false; 10 | } 11 | } 12 | 13 | public ApiMarketOrder(ApiMarketWay way, int quantity) 14 | { 15 | this.Quantity = quantity; 16 | this.Way = way; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /CSharp/OtherTeam.StandardizedMarketGatewayAPI/ApiMarketWay.cs: -------------------------------------------------------------------------------- 1 | namespace OtherTeam.StandardizedMarketGatewayAPI 2 | { 3 | /// 4 | /// Sell or Buy way for Orders. 5 | /// 6 | public enum ApiMarketWay 7 | { 8 | /// 9 | /// The Buy way. 10 | /// 11 | Buy, 12 | 13 | /// 14 | /// The Sell way. 15 | /// 16 | Sell 17 | } 18 | } -------------------------------------------------------------------------------- /CSharp/OtherTeam.StandardizedMarketGatewayAPI/ApiOrder.cs: -------------------------------------------------------------------------------- 1 | namespace OtherTeam.StandardizedMarketGatewayAPI 2 | { 3 | using System; 4 | 5 | public class ApiOrder 6 | { 7 | public int Quantity { get; protected set; } 8 | 9 | public ApiMarketWay Way { get; protected set; } 10 | 11 | public bool AllowPartialExecution { get; protected set; } 12 | 13 | private void Send() 14 | { 15 | throw new NotImplementedException(); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /CSharp/OtherTeam.StandardizedMarketGatewayAPI/ApiOrderFailedEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace OtherTeam.StandardizedMarketGatewayAPI 2 | { 3 | using System; 4 | 5 | /// 6 | /// Event data for DealExecuted event. 7 | /// 8 | public class ApiOrderFailedEventArgs : EventArgs 9 | { 10 | public string MarketName { get; private set; } 11 | 12 | public string FailureCause { get; private set; } 13 | 14 | public ApiOrderFailedEventArgs(string marketName, string failureCause) 15 | { 16 | this.MarketName = marketName; 17 | this.FailureCause = failureCause; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /CSharp/OtherTeam.StandardizedMarketGatewayAPI/OtherTeam.StandardizedMarketGatewayAPI.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {FE2D8118-AFD3-4005-A6D5-C1D240DAD3E4} 8 | Library 9 | Properties 10 | OtherTeam.StandardizedMarketGatewayAPI 11 | OtherTeam.StandardizedMarketGatewayAPI 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 60 | -------------------------------------------------------------------------------- /CSharp/OtherTeam.StandardizedMarketGatewayAPI/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("OtherTeam.StandardizedMarketGatewayAPI")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("OtherTeam.StandardizedMarketGatewayAPI")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c777c093-158c-4a25-b245-84b2f5ab65d2")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /CSharp/Settings.StyleCop: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hashtable 5 | enum 6 | gzip 7 | nullable 8 | struct 9 | sut 10 | uint 11 | ulong 12 | ushort 13 | vs 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | False 22 | 23 | 24 | 25 | 26 | False 27 | 28 | 29 | 30 | 31 | False 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | False 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Console/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Console/Program.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Console 2 | { 3 | using System; 4 | 5 | using OtherTeam.StandardizedMarketGatewayAPI; 6 | using SimpleOrderRouting.Infra; 7 | 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | var marketA = new ApiMarketGateway("NYSE (New York)", sellQuantity: 150, sellPrice: 100M); 13 | var marketB = new ApiMarketGateway("CME (Chicago)", sellQuantity: 55, sellPrice: 101M); 14 | 15 | var investorAdapter = CompositionRootHelper.ComposeTheHexagon(marketA, marketB); 16 | 17 | System.Console.WriteLine("SOR connected to markets: {0} and {1}", marketA.MarketName, marketB.MarketName); 18 | 19 | var investorInstructionDto = new InvestorInstructionDto(Way.Buy, quantity: 125, price: 100M); 20 | 21 | System.Console.WriteLine(); 22 | System.Console.WriteLine("Type 'Enter' to submit the following investor instruction: [{0}]\n\n", investorInstructionDto); 23 | System.Console.ReadLine(); 24 | 25 | investorAdapter.Route(investorInstructionDto, arg => { System.Console.WriteLine("Instruction executed: [{0}]", arg); }, eventArgs => {}); 26 | 27 | System.Console.WriteLine(); 28 | System.Console.WriteLine("Type 'Enter' to exit"); 29 | System.Console.ReadLine(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Console/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SimpleOrderRouting.Console")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SimpleOrderRouting.Console")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("fd7fc9da-f31f-48d1-877a-ed85d4cddbd8")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Console/SimpleOrderRouting.Console.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F20EBD6E-C774-4856-91D5-1BA43005513D} 8 | Exe 9 | Properties 10 | SimpleOrderRouting.Console 11 | SimpleOrderRouting.Console 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | {fe2d8118-afd3-4005-a6d5-c1d240dad3e4} 53 | OtherTeam.StandardizedMarketGatewayAPI 54 | 55 | 56 | {4f66c7d2-8cbd-4280-9a2d-6555e276c6a7} 57 | SimpleOrderRouting.Domain 58 | 59 | 60 | {00dd3731-e815-4770-be17-4f17bfec4171} 61 | SimpleOrderRouting.Infra 62 | 63 | 64 | 65 | 72 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/ICanReceiveMarketData.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting 2 | { 3 | using System; 4 | 5 | using SimpleOrderRouting.Markets.Feeds; 6 | using SimpleOrderRouting.Markets.Orders; 7 | 8 | /// 9 | /// Allows to receive MarketData events. 10 | /// 11 | public interface ICanReceiveMarketData 12 | { 13 | 14 | /// 15 | /// Occurs when market data is updated for an Instrument. 16 | /// 17 | event EventHandler InstrumentMarketDataUpdated; 18 | 19 | /// 20 | /// Occurs when one order failed on a Market. 21 | /// 22 | event EventHandler OrderFailedOnAMarket; 23 | 24 | void Subscribe(string marketName); 25 | } 26 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/ICanRouteOrders.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting 2 | { 3 | using System; 4 | 5 | using SimpleOrderRouting.Markets.Orders; 6 | 7 | /// 8 | /// Allows to create and route Orders on Market venues. 9 | /// 10 | public interface ICanRouteOrders 11 | { 12 | IOrder CreateMarketOrder(OrderDescription orderDescription); 13 | 14 | IOrder CreateLimitOrder(OrderDescription orderDescription); 15 | 16 | void Route(OrderBasket basketOrder); 17 | 18 | /// 19 | /// Occurs when one order is executed. 20 | /// 21 | event EventHandler OrderExecuted; 22 | 23 | /// 24 | /// Occurs when one order failed. 25 | /// 26 | event EventHandler OrderFailed; 27 | } 28 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/IHandleInvestorInstructions.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting 2 | { 3 | using System; 4 | 5 | using SimpleOrderRouting.Investors; 6 | 7 | /// 8 | /// Provides an integration point for all investor side use cases. 9 | /// 10 | public interface IHandleInvestorInstructions 11 | { 12 | void Route(InvestorInstruction investorInstruction, Action executedCallback, Action failureCallback); 13 | } 14 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/IOrder.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: Ozgur DEVELIOGLU (@Zgurrr), Cyrille DUPUYDAUBY 4 | // (@Cyrdup), Tomasz JASKULA (@tjaskula), Thomas PIERRAIN (@tpierrain) 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // -------------------------------------------------------------------------------------------------------------------- 16 | namespace SimpleOrderRouting 17 | { 18 | using System; 19 | 20 | using SimpleOrderRouting.Markets.Orders; 21 | 22 | /// 23 | /// Orders to buy or sell a given quantity of a product. 24 | /// 25 | public interface IOrder 26 | { 27 | event EventHandler OrderExecuted; 28 | 29 | // TODO: Maybe not necessary if we change the Send() signature to inlcude the notification. 30 | event EventHandler OrderFailed; 31 | 32 | Way Way { get; } 33 | 34 | int Quantity { get; } 35 | 36 | bool AllowPartialExecution { get; } 37 | 38 | void Send(); 39 | } 40 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/IProvideMarkets.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting 2 | { 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// Lists the names of available markets. 7 | /// 8 | public interface IProvideMarkets 9 | { 10 | IEnumerable GetAvailableMarketNames(); 11 | } 12 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/ISolveInvestorInstructions.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: Ozgur DEVELIOGLU (@Zgurrr), Cyrille DUPUYDAUBY 4 | // (@Cyrdup), Tomasz JASKULA (@tjaskula), Thomas PIERRAIN (@tpierrain) 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // -------------------------------------------------------------------------------------------------------------------- 16 | namespace SimpleOrderRouting 17 | { 18 | using SimpleOrderRouting.Investors; 19 | using SimpleOrderRouting.Markets.Orders; 20 | 21 | /// 22 | /// Transforms an into an . 23 | /// 24 | public interface ISolveInvestorInstructions 25 | { 26 | // TODO: remove the reference to ICanRouteOrder (currently requested for the OrderBasket creation;-( 27 | /// 28 | /// Build the description of the orders needed to fulfill an which 29 | /// is aggregated within an instance. 30 | /// 31 | /// The instance that aggregates the . 32 | /// The can route orders (temp hack that should be removed afterwards). 33 | /// 34 | /// An containing all the orders to be routed in order to fulfill the initial . 35 | /// 36 | OrderBasket Solve(InstructionExecutionContext instructionExecutionContext, ICanRouteOrders canRouteOrders); 37 | } 38 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/InvestorIntructionCallback.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting 23 | { 24 | using System; 25 | 26 | using SimpleOrderRouting.Markets.Orders; 27 | 28 | /// 29 | /// Allows to raise Callbacks on a given investor instruction. 30 | /// 31 | public class InvestorIntructionCallback 32 | { 33 | private readonly Action executedCallback; 34 | 35 | private readonly Action failureCallback; 36 | 37 | public InvestorIntructionCallback(Action executedCallback, Action failureCallback) 38 | { 39 | this.executedCallback = executedCallback; 40 | this.failureCallback = failureCallback; 41 | } 42 | 43 | public void OnExecuted(object sender, OrderExecutedEventArgs e) 44 | { 45 | this.executedCallback(e); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Investors/InstructionExecutionContext.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | namespace SimpleOrderRouting.Investors 22 | { 23 | using System; 24 | 25 | using SimpleOrderRouting.Markets.Orders; 26 | 27 | /// 28 | /// 1 to 1 relationship with an . Keeps the current state of the instruction execution. 29 | /// Entity 30 | /// 31 | public class InstructionExecutionContext 32 | { 33 | public InvestorInstruction Instruction { get; private set; } 34 | 35 | private readonly Action instructionExecutedCallBack; 36 | 37 | private readonly Action instructionFailedCallback; 38 | 39 | private readonly int initialQuantity; 40 | 41 | public InstructionExecutionContext(InvestorInstruction investorInstruction, Action instructionExecutedCallBack, Action instructionFailedCallback) 42 | { 43 | this.Instruction = investorInstruction; 44 | this.instructionExecutedCallBack = instructionExecutedCallBack; 45 | this.instructionFailedCallback = instructionFailedCallback; 46 | this.initialQuantity = investorInstruction.Quantity; 47 | this.RemainingQuantityToBeExecuted = investorInstruction.Quantity; 48 | this.Price = investorInstruction.Price; 49 | this.Way = investorInstruction.Way; 50 | this.AllowPartialExecution = investorInstruction.AllowPartialExecution; 51 | } 52 | 53 | public int RemainingQuantityToBeExecuted { get; private set; } 54 | 55 | public decimal Price { get; private set; } 56 | 57 | public Way Way { get; private set; } 58 | 59 | public bool AllowPartialExecution { get; private set; } 60 | 61 | /// 62 | /// Records that an order has been executed and calls the instructionExecutedCallBack if the Instruction is fully executed. 63 | /// 64 | /// The executed quantity. 65 | public void RecordOrderExecution(int quantity) 66 | { 67 | var previousRemainingQuantityToBeExecuted = this.RemainingQuantityToBeExecuted; 68 | 69 | this.RemainingQuantityToBeExecuted -= quantity; 70 | 71 | if (this.RemainingQuantityToBeExecuted == 0) 72 | { 73 | this.instructionExecutedCallBack(new InvestorInstructionExecutedEventArgs(this.Way, this.initialQuantity, this.Price)); 74 | } 75 | else if (this.RemainingQuantityToBeExecuted < 0) 76 | { 77 | throw new ApplicationException(string.Format("Executed more than the investor instruction has requested. Previous remaining quantity to be executed: {0}, latest executed quantity: {1}. New remaining quantity to be executed: {2}.", previousRemainingQuantityToBeExecuted, quantity, this.RemainingQuantityToBeExecuted)); 78 | } 79 | } 80 | 81 | public bool ShouldTheInstructionBeContinued() 82 | { 83 | return this.Instruction.GoodTill != null && this.Instruction.GoodTill > DateTime.Now && this.RemainingQuantityToBeExecuted > 0; 84 | } 85 | 86 | public void DeclareFailure(OrderFailedEventArgs orderFailedEventArgs) 87 | { 88 | this.instructionFailedCallback(orderFailedEventArgs.Reason); 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Investors/InvestorInstruction.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | namespace SimpleOrderRouting.Investors 22 | { 23 | using System; 24 | 25 | /// 26 | /// Trading instruction given to the SOR on the investor-side. 27 | /// 28 | public class InvestorInstruction 29 | { 30 | public InvestorInstruction(long investorInstructionIdentifier, Way way, int quantity, decimal price, bool allowPartialExecution = false, DateTime? goodTill = null) 31 | { 32 | this.Way = way; 33 | this.Quantity = quantity; 34 | this.Price = price; 35 | this.AllowPartialExecution = allowPartialExecution; 36 | this.GoodTill = goodTill; 37 | 38 | this.InvestorInstructionIdentifier = investorInstructionIdentifier; 39 | } 40 | 41 | public long InvestorInstructionIdentifier { get; private set; } 42 | 43 | public DateTime? GoodTill { get; private set; } 44 | 45 | public bool AllowPartialExecution { get; private set; } 46 | 47 | public decimal Price { get; private set; } 48 | 49 | public int Quantity { get; private set; } 50 | 51 | public Way Way { get; private set; } 52 | 53 | public static bool operator ==(InvestorInstruction left, InvestorInstruction right) 54 | { 55 | return Equals(left, right); 56 | } 57 | 58 | public static bool operator !=(InvestorInstruction left, InvestorInstruction right) 59 | { 60 | return !Equals(left, right); 61 | } 62 | 63 | protected bool Equals(InvestorInstruction other) 64 | { 65 | return this.InvestorInstructionIdentifier == other.InvestorInstructionIdentifier && this.GoodTill.Equals(other.GoodTill) && this.AllowPartialExecution == other.AllowPartialExecution && this.Price == other.Price && this.Quantity == other.Quantity && this.Way == other.Way; 66 | } 67 | 68 | public override bool Equals(object obj) 69 | { 70 | if (ReferenceEquals(null, obj)) 71 | { 72 | return false; 73 | } 74 | if (ReferenceEquals(this, obj)) 75 | { 76 | return true; 77 | } 78 | if (obj.GetType() != this.GetType()) 79 | { 80 | return false; 81 | } 82 | return this.Equals((InvestorInstruction)obj); 83 | } 84 | 85 | public override int GetHashCode() 86 | { 87 | unchecked 88 | { 89 | var hashCode = this.InvestorInstructionIdentifier.GetHashCode(); 90 | hashCode = (hashCode * 397) ^ this.GoodTill.GetHashCode(); 91 | hashCode = (hashCode * 397) ^ this.AllowPartialExecution.GetHashCode(); 92 | hashCode = (hashCode * 397) ^ this.Price.GetHashCode(); 93 | hashCode = (hashCode * 397) ^ this.Quantity; 94 | hashCode = (hashCode * 397) ^ (int)this.Way; 95 | return hashCode; 96 | } 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Investors/InvestorInstructionExecutedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SimpleOrderRouting.Investors 4 | { 5 | /// 6 | /// Event data for InvestorInstructionExecuted event. 7 | /// 8 | public class InvestorInstructionExecutedEventArgs : EventArgs 9 | { 10 | public InvestorInstructionExecutedEventArgs(Way way, int quantity, decimal price) 11 | { 12 | this.Quantity = quantity; 13 | this.Price = price; 14 | this.Way = way; 15 | } 16 | 17 | public int Quantity { get; private set; } 18 | 19 | public decimal Price { get; private set; } 20 | 21 | public Way Way { get; private set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Investors/InvestorInstructionStatus.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Investors 23 | { 24 | public enum InvestorInstructionStatus 25 | { 26 | Executed, 27 | 28 | PartiallyExecuted, 29 | 30 | Failed 31 | } 32 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Markets/Feeds/MarketDataUpdatedArgs.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Markets.Feeds 2 | { 3 | using System; 4 | using SimpleOrderRouting.Markets.Orders; 5 | 6 | public class MarketDataUpdatedArgs : EventArgs 7 | { 8 | public MarketDataUpdatedArgs(string marketName, decimal price, int quantity) 9 | { 10 | this.Quantity = quantity; 11 | this.Price = price; 12 | this.MarketName = marketName; 13 | } 14 | 15 | public string MarketName { get; private set; } 16 | 17 | // TODO : introduce the concept of various instruments 18 | public InstrumentIdentifier InstrumentIdentifier { get; private set; } 19 | 20 | public decimal Price { get; private set; } 21 | public int Quantity { get; private set; } 22 | } 23 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Markets/MarketInfo.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | namespace SimpleOrderRouting.Markets 22 | { 23 | /// 24 | /// Aggregates information about a given Market (e.g. # of failures, etc.). 25 | /// 26 | public class MarketInfo 27 | { 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | /// Name of the market. 32 | /// The sell quantity. 33 | /// The sell price. 34 | public MarketInfo(string marketName, int sellQuantity, decimal sellPrice) 35 | { 36 | this.MarketName = marketName; 37 | this.SellQuantity = sellQuantity; 38 | this.SellPrice = sellPrice; 39 | } 40 | 41 | public string MarketName { get; private set; } 42 | 43 | public int SellQuantity { get; private set; } 44 | 45 | public decimal SellPrice { get; private set; } 46 | 47 | /// 48 | /// Gets or sets the number of failures for orders we received from this market. 49 | /// 50 | /// 51 | /// The number of failures for orders we received from this market. 52 | /// 53 | public int OrdersFailureCount { get; set; } 54 | } 55 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Markets/MarketSnapshot.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | namespace SimpleOrderRouting.Markets 22 | { 23 | using System.Collections.Generic; 24 | 25 | /// 26 | /// Snapshot of multiple Markets venues. 27 | /// 28 | public class MarketSnapshot 29 | { 30 | public MarketSnapshot(IList marketInfos) 31 | { 32 | this.MarketInfos = marketInfos; 33 | } 34 | 35 | public IList MarketInfos { get; private set; } 36 | 37 | } 38 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Markets/MarketSnapshotProvider.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | namespace SimpleOrderRouting.Markets 22 | { 23 | using System.Collections.Generic; 24 | using System.Linq; 25 | 26 | using SimpleOrderRouting.Markets.Feeds; 27 | 28 | /// 29 | /// Provide instances. 30 | /// 31 | public class MarketSnapshotProvider 32 | { 33 | private readonly Dictionary lastMarketUpdates = new Dictionary(); 34 | 35 | public MarketSnapshotProvider(IEnumerable marketNames, ICanReceiveMarketData canReceiveMarketData) 36 | { 37 | canReceiveMarketData.InstrumentMarketDataUpdated += this.InstrumentMarketDataUpdated; 38 | canReceiveMarketData.OrderFailedOnAMarket += this.canReceiveMarketData_OrderFailedOnAMarket; 39 | 40 | foreach (var marketName in marketNames) 41 | { 42 | // TODO : Get rid of the hack (casting to concrete class) 43 | canReceiveMarketData.Subscribe(marketName); 44 | } 45 | } 46 | 47 | void canReceiveMarketData_OrderFailedOnAMarket(object sender, Orders.OrderFailedEventArgs e) 48 | { 49 | this.DeclareFailure(e.MarketName); 50 | } 51 | 52 | private void InstrumentMarketDataUpdated(object sender, MarketDataUpdatedArgs marketDataUpdatedArgs) 53 | { 54 | this.lastMarketUpdates[marketDataUpdatedArgs.MarketName] = new MarketInfo(marketDataUpdatedArgs.MarketName, marketDataUpdatedArgs.Quantity, marketDataUpdatedArgs.Price); 55 | } 56 | 57 | public MarketSnapshot GetSnapshot() 58 | { 59 | return new MarketSnapshot(this.lastMarketUpdates.Values.ToList()); 60 | } 61 | 62 | private void DeclareFailure(string marketName) 63 | { 64 | this.lastMarketUpdates.First(m => m.Key == marketName).Value.OrdersFailureCount++; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Markets/Orders/DealExecutedEventArgs.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: Ozgur DEVELIOGLU (@Zgurrr), Cyrille DUPUYDAUBY 4 | // (@Cyrdup), Tomasz JASKULA (@tjaskula), Thomas PIERRAIN (@tpierrain) 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // -------------------------------------------------------------------------------------------------------------------- 16 | namespace SimpleOrderRouting.Markets.Orders 17 | { 18 | using System; 19 | 20 | /// 21 | /// Event data for DealExecuted event. 22 | /// 23 | public class DealExecutedEventArgs : EventArgs 24 | { 25 | public DealExecutedEventArgs(decimal price, int quantity) 26 | { 27 | this.Price = price; 28 | this.Quantity = quantity; 29 | } 30 | 31 | public decimal Price { get; private set; } 32 | 33 | public int Quantity { get; private set; } 34 | } 35 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Markets/Orders/InstrumentIdentifier.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Markets.Orders 2 | { 3 | public class InstrumentIdentifier 4 | { 5 | private readonly string instrumentIdentifier; 6 | 7 | public InstrumentIdentifier(string instrumentIdentifier) 8 | { 9 | this.instrumentIdentifier = instrumentIdentifier; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Markets/Orders/OrderBasket.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | namespace SimpleOrderRouting.Markets.Orders 22 | { 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | 27 | /// 28 | /// Aggregates multiple instances. 29 | /// OrderBasket is a composite (pattern). 30 | /// 31 | public class OrderBasket : IOrder 32 | { 33 | public List OrdersDescriptions { get; private set; } 34 | 35 | private readonly ICanRouteOrders canRouteOrders; 36 | 37 | /// 38 | /// Initializes a new instance of the class. 39 | /// 40 | /// The orders descriptions. 41 | /// The can route orders. 42 | public OrderBasket(List ordersDescriptions, ICanRouteOrders canRouteOrders) 43 | { 44 | this.OrdersDescriptions = ordersDescriptions; 45 | this.canRouteOrders = canRouteOrders; 46 | 47 | if (ordersDescriptions.Count > 0) 48 | { 49 | this.Way = ordersDescriptions[0].OrderWay; 50 | 51 | foreach (var orderDescription in ordersDescriptions) 52 | { 53 | if (orderDescription.AllowPartialExecution) 54 | { 55 | this.AllowPartialExecution = true; 56 | } 57 | 58 | this.Quantity += orderDescription.Quantity; 59 | } 60 | } 61 | } 62 | 63 | public event EventHandler OrderExecuted; 64 | 65 | public event EventHandler OrderFailed; 66 | 67 | public bool AllowPartialExecution { get; private set; } 68 | 69 | public int Quantity { get; private set; } 70 | 71 | public Way Way { get; private set; } 72 | 73 | // TODO: Change the IOrder interface to always include the notification. 74 | public void Send() 75 | { 76 | var failures = new List(this.OrdersDescriptions.Count); 77 | 78 | foreach (var orderDescription in this.OrdersDescriptions) 79 | { 80 | // TODO: refactor this to prevent this domain object to rely too much on ICanRouterOrders things... 81 | var limitOrder = this.canRouteOrders.CreateLimitOrder(orderDescription); 82 | 83 | EventHandler orderExecuted = (sender, executedEventArgs) => this.OnOrderExecuted(executedEventArgs); 84 | EventHandler orderFailed = (sender, reason) => failures.Add(reason); 85 | 86 | limitOrder.OrderExecuted += orderExecuted; 87 | limitOrder.OrderFailed += orderFailed; 88 | 89 | limitOrder.Send(); 90 | 91 | limitOrder.OrderExecuted -= orderExecuted; 92 | limitOrder.OrderFailed -= orderFailed; 93 | } 94 | 95 | if (failures.Count > 0) 96 | { 97 | this.RaiseOrderFailed(failures); 98 | } 99 | } 100 | 101 | private void OnOrderExecuted(DealExecutedEventArgs e) 102 | { 103 | this.RaiseOrderExecuted(e); 104 | } 105 | 106 | private void RaiseOrderFailed(List failures) 107 | { 108 | var onOrderFailed = this.OrderFailed; 109 | if (onOrderFailed != null) 110 | { 111 | onOrderFailed(this, failures.First()); 112 | } 113 | } 114 | 115 | private void RaiseOrderExecuted(DealExecutedEventArgs e) 116 | { 117 | var onOrderExecuted = this.OrderExecuted; 118 | if (onOrderExecuted != null) 119 | { 120 | onOrderExecuted(this, e); 121 | } 122 | } 123 | } 124 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Markets/Orders/OrderDescription.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: Ozgur DEVELIOGLU (@Zgurrr), Cyrille DUPUYDAUBY 4 | // (@Cyrdup), Tomasz JASKULA (@tjaskula), Thomas PIERRAIN (@tpierrain) 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // -------------------------------------------------------------------------------------------------------------------- 16 | namespace SimpleOrderRouting.Markets.Orders 17 | { 18 | /// 19 | /// Caracteristics of an Order to be passed on a market. 20 | /// 21 | public struct OrderDescription 22 | { 23 | // TODO: does OrderDescription need to expose its corresponding order type somehow (i.e. marketorder, limitorder)? 24 | 25 | public string TargetMarketName; 26 | 27 | public Way OrderWay; 28 | 29 | public int Quantity { get; private set; } 30 | 31 | public decimal OrderPrice; 32 | 33 | public bool AllowPartialExecution; 34 | 35 | public OrderDescription(string targetMarketName, Way orderWay, int quantity, decimal orderPrice, bool allowPartialExecution) 36 | : this() 37 | { 38 | this.TargetMarketName = targetMarketName; 39 | this.OrderWay = orderWay; 40 | this.Quantity = quantity; 41 | this.OrderPrice = orderPrice; 42 | this.AllowPartialExecution = allowPartialExecution; 43 | } 44 | 45 | public override string ToString() 46 | { 47 | return string.Format("Order description: TargetMarketName={0} - quantity={1} - Way={2} - Price={3} - AllowPartialExecution={4}.", this.TargetMarketName, this.Quantity, this.OrderWay, this.OrderPrice, this.AllowPartialExecution); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Markets/Orders/OrderExecutedEventArgs.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: Ozgur DEVELIOGLU (@Zgurrr), Cyrille DUPUYDAUBY 4 | // (@Cyrdup), Tomasz JASKULA (@tjaskula), Thomas PIERRAIN (@tpierrain) 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // -------------------------------------------------------------------------------------------------------------------- 16 | namespace SimpleOrderRouting.Markets.Orders 17 | { 18 | /// 19 | /// Event data for OrderExecuted event. 20 | /// 21 | public class OrderExecutedEventArgs 22 | { 23 | public OrderExecutedEventArgs(Way way, int quantity, decimal price) 24 | { 25 | this.Quantity = quantity; 26 | this.Price = price; 27 | this.Way = way; 28 | } 29 | 30 | public int Quantity { get; private set; } 31 | 32 | public decimal Price { get; private set; } 33 | 34 | public Way Way { get; private set; } 35 | } 36 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Markets/Orders/OrderFailedEventArgs.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | namespace SimpleOrderRouting.Markets.Orders 22 | { 23 | /// 24 | /// Event data for OrderFailed event. 25 | /// 26 | public class OrderFailedEventArgs 27 | { 28 | public OrderFailedEventArgs(string marketName, string reason) 29 | { 30 | this.Reason = reason; 31 | this.MarketName = marketName; 32 | } 33 | 34 | public string MarketName { get; private set; } 35 | 36 | public string Reason { get; private set; } 37 | } 38 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SimpleOrderRouting.Interfaces")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SimpleOrderRouting.Interfaces")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("2e31b1b3-60a8-422c-ba1d-f404a5e851d3")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/SimpleOrderRouting.Domain.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {4F66C7D2-8CBD-4280-9A2D-6555E276C6A7} 8 | Library 9 | Properties 10 | SimpleOrderRouting 11 | SimpleOrderRouting.Domain 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 77 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/SmartOrderRoutingEngine.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | namespace SimpleOrderRouting 22 | { 23 | using System; 24 | using System.Collections.Generic; 25 | 26 | using SimpleOrderRouting.Investors; 27 | using SimpleOrderRouting.Markets; 28 | using SimpleOrderRouting.Markets.Orders; 29 | using SimpleOrderRouting.SolvingStrategies; 30 | 31 | /// 32 | /// Provides access to the various services offered by the external market venues. 33 | /// Manages incoming InvestorInstructions and monitor their lifecycle. 34 | /// Is responsible for the consistency of the open positions (i.e. alive orders) that are present on every markets. 35 | /// 36 | public class SmartOrderRoutingEngine : IHandleInvestorInstructions 37 | { 38 | private readonly ICanRouteOrders routeOrders; 39 | private readonly MarketSnapshotProvider marketSnapshotProvider; 40 | 41 | /// 42 | /// Initializes a new instance of the class. 43 | /// 44 | /// The markets provider. 45 | /// The order routing. 46 | /// The market data provider. 47 | public SmartOrderRoutingEngine(IProvideMarkets marketsProvider, ICanRouteOrders routeOrders, ICanReceiveMarketData marketDataProvider) 48 | { 49 | this.routeOrders = routeOrders; 50 | var availableMarkets = marketsProvider.GetAvailableMarketNames(); 51 | this.marketSnapshotProvider = new MarketSnapshotProvider(availableMarkets, marketDataProvider); 52 | } 53 | 54 | public void Route(InvestorInstruction investorInstruction, Action instructionExecutedCallback, Action failureCallback) 55 | { 56 | // Prepares to feedback the investor 57 | var instructionExecutionContext = new InstructionExecutionContext(investorInstruction, instructionExecutedCallback, failureCallback); 58 | 59 | this.routeOrders.OrderExecuted += this.WhenOneOrderIsExecuted(instructionExecutionContext); 60 | this.routeOrders.OrderFailed += this.WhenOneOrderFailed(instructionExecutionContext); 61 | 62 | this.RouteImpl(instructionExecutionContext); 63 | 64 | this.routeOrders.OrderExecuted -= this.WhenOneOrderIsExecuted(instructionExecutionContext); 65 | this.routeOrders.OrderFailed -= this.WhenOneOrderFailed(instructionExecutionContext); 66 | } 67 | 68 | private void RouteImpl(InstructionExecutionContext instructionExecutionContext) 69 | { 70 | // 1. Prepare the corresponding OrderBasket (via solver) 71 | var solver = new MarketSweepSolver(this.marketSnapshotProvider); 72 | var orderBasket = solver.Solve(instructionExecutionContext, this.routeOrders); 73 | 74 | // 2. Route the OrderBasket 75 | this.routeOrders.Route(orderBasket); 76 | } 77 | 78 | private EventHandler WhenOneOrderIsExecuted(InstructionExecutionContext instructionExecutionContext) 79 | { 80 | // TODO: must process the message only if it's related to the proper instruction 81 | return (sender, dealExecuted) => instructionExecutionContext.RecordOrderExecution(dealExecuted.Quantity); 82 | } 83 | 84 | private EventHandler WhenOneOrderFailed(InstructionExecutionContext instructionExecutionContext) 85 | { 86 | // TODO: must process the message only if it's related to the proper instruction 87 | return (sender, orderFailed) => this.OnOrderFailed(orderFailed, instructionExecutionContext); 88 | } 89 | 90 | private void OnOrderFailed(OrderFailedEventArgs reason, InstructionExecutionContext instructionExecutionContext) 91 | { 92 | if (instructionExecutionContext.ShouldTheInstructionBeContinued()) 93 | { 94 | this.RetryInvestorInstruction(instructionExecutionContext); 95 | } 96 | else 97 | { 98 | instructionExecutionContext.DeclareFailure(reason); 99 | } 100 | } 101 | 102 | private void RetryInvestorInstruction(InstructionExecutionContext instructionExecutionContext) 103 | { 104 | this.RouteImpl(instructionExecutionContext); 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/SolvingStrategies/MarketSweepSolver.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: Ozgur DEVELIOGLU (@Zgurrr), Cyrille DUPUYDAUBY 4 | // (@Cyrdup), Tomasz JASKULA (@tjaskula), Thomas PIERRAIN (@tpierrain) 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // -------------------------------------------------------------------------------------------------------------------- 16 | namespace SimpleOrderRouting.SolvingStrategies 17 | { 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | 22 | using SimpleOrderRouting.Investors; 23 | using SimpleOrderRouting.Markets; 24 | using SimpleOrderRouting.Markets.Orders; 25 | 26 | /// 27 | /// Transforms an into an that 28 | /// will allow us to route following a weight average strategy on 29 | /// the relevant markets. 30 | /// 31 | public class MarketSweepSolver : ISolveInvestorInstructions 32 | { 33 | private const int MaxSupportedFailuresPerMarket = 3; 34 | 35 | private readonly MarketSnapshotProvider marketSnapshotProvider; 36 | 37 | /// 38 | /// Initializes a new instance of the class. 39 | /// 40 | /// The market information. 41 | public MarketSweepSolver(MarketSnapshotProvider marketSnapshotProvider) 42 | { 43 | this.marketSnapshotProvider = marketSnapshotProvider; 44 | } 45 | 46 | /// 47 | /// Build the description of the orders needed to fulfill an which 48 | /// is aggregated within an instance. 49 | /// 50 | /// The instance that aggregates the . 51 | /// 52 | /// 53 | /// An containing all the orders to be routed in order to fulfill the initial . 54 | /// 55 | public OrderBasket Solve(InstructionExecutionContext instructionExecutionContext, ICanRouteOrders canRouteOrders) 56 | { 57 | // Checks liquidities available to weighted average for execution 58 | int remainingQuantityToBeExecuted = instructionExecutionContext.RemainingQuantityToBeExecuted; 59 | decimal requestedPrice = instructionExecutionContext.Price; 60 | 61 | var validMarkets = this.GetValidMarkets(requestedPrice); 62 | int availableQuantityOnMarkets = this.ComputeAvailableQuantityForThisPrice(validMarkets); 63 | 64 | if (availableQuantityOnMarkets == 0) 65 | { 66 | return new OrderBasket(new List(), canRouteOrders); 67 | } 68 | 69 | var ordersDescription = GenerateOrdersDescription(instructionExecutionContext, remainingQuantityToBeExecuted, validMarkets, requestedPrice, availableQuantityOnMarkets); 70 | 71 | return new OrderBasket(ordersDescription, canRouteOrders); 72 | } 73 | 74 | private static List GenerateOrdersDescription(InstructionExecutionContext instructionExecutionContext, int remainingQuantityToBeExecuted, IEnumerable validMarkets, decimal requestedPrice, int availableQuantityOnMarkets) 75 | { 76 | var ordersDescription = new List(); 77 | 78 | if (remainingQuantityToBeExecuted == 1) 79 | { 80 | ordersDescription.Add(new OrderDescription(validMarkets.First(m => m.SellQuantity >= 1).MarketName, instructionExecutionContext.Way, remainingQuantityToBeExecuted, requestedPrice, instructionExecutionContext.AllowPartialExecution)); 81 | } 82 | else 83 | { 84 | var ratio = remainingQuantityToBeExecuted / (decimal)availableQuantityOnMarkets; 85 | 86 | // ReSharper disable once LoopCanBeConvertedToQuery 87 | foreach (var marketInfo in validMarkets) 88 | { 89 | var convertedMarketQuantity = Math.Round(marketInfo.SellQuantity * ratio, 2, MidpointRounding.AwayFromZero); 90 | var quantityToExecute = Convert.ToInt32(convertedMarketQuantity); 91 | 92 | if (quantityToExecute > 0) 93 | { 94 | ordersDescription.Add(new OrderDescription(marketInfo.MarketName, instructionExecutionContext.Way, quantityToExecute, requestedPrice, instructionExecutionContext.AllowPartialExecution)); 95 | } 96 | } 97 | } 98 | 99 | if (ordersDescription.Count <= 0) 100 | { 101 | throw new InvalidOperationException(string.Format("No order description has been created while there is still {0} quantity to be executed (available quantity on the market is {1}).", remainingQuantityToBeExecuted, availableQuantityOnMarkets)); 102 | } 103 | 104 | return ordersDescription; 105 | } 106 | 107 | private IEnumerable GetValidMarkets(decimal requestedPrice) 108 | { 109 | var allMarkets = this.marketSnapshotProvider.GetSnapshot(); 110 | return allMarkets.MarketInfos.Where(m => m.OrdersFailureCount < MaxSupportedFailuresPerMarket && requestedPrice >= m.SellPrice); 111 | } 112 | 113 | private int ComputeAvailableQuantityForThisPrice(IEnumerable validMarkets) 114 | { 115 | var availableQuantityOnMarkets = 0; 116 | 117 | foreach (var marketInfo in validMarkets) 118 | { 119 | availableQuantityOnMarkets += marketInfo.SellQuantity; 120 | } 121 | 122 | return availableQuantityOnMarkets; 123 | } 124 | } 125 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Domain/Way.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: Ozgur DEVELIOGLU (@Zgurrr), Cyrille DUPUYDAUBY 4 | // (@Cyrdup), Tomasz JASKULA (@tjaskula), Thomas PIERRAIN (@tpierrain) 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // -------------------------------------------------------------------------------------------------------------------- 16 | namespace SimpleOrderRouting 17 | { 18 | /// 19 | /// Sell or Buy way for Orders. 20 | /// 21 | public enum Way 22 | { 23 | /// 24 | /// The Buy way. 25 | /// 26 | Buy, 27 | 28 | /// 29 | /// The Sell way. 30 | /// 31 | Sell 32 | } 33 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/CompositionRootHelper.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Thomas PIERRAIN (@tpierrain) 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // -------------------------------------------------------------------------------------------------------------------- 17 | 18 | namespace SimpleOrderRouting.Infra 19 | { 20 | using OtherTeam.StandardizedMarketGatewayAPI; 21 | 22 | public static class CompositionRootHelper 23 | { 24 | /// 25 | /// Acts like a composition root for the SOR Hexagonal Architecture. 26 | /// 27 | /// The list of ApiMarketGateway the SOR must interact with. 28 | /// The adapter we must use as Investors in order to give investment instructions. 29 | public static InvestorInstructionsAdapter ComposeTheHexagon(params ApiMarketGateway[] marketGateways) 30 | { 31 | // Step1: instantiates the adapter(s) the (SOR) domain will need to work with through the Dependency Inversion principle. 32 | var marketGatewaysAdapter = new MarketsAdapter(marketGateways); 33 | 34 | // Step2: instantiates the SOR domain entry point. 35 | var sor = new SmartOrderRoutingEngine(marketGatewaysAdapter, marketGatewaysAdapter, marketGatewaysAdapter); 36 | 37 | // Step3: instantiates the adapters we will use to interact with our domain. 38 | var investorInstructionAdapter = new InvestorInstructionsAdapter(sor); 39 | 40 | return investorInstructionAdapter; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Investors/InstructionExecutedDto.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | namespace SimpleOrderRouting.Infra 22 | { 23 | using System; 24 | 25 | /// 26 | /// Event data for InstructionExecuted. 27 | /// 28 | public class InstructionExecutedDto 29 | { 30 | public InstructionExecutedDto(InvestorWay way, decimal price, int quantity) 31 | { 32 | this.Quantity = quantity; 33 | this.Price = price; 34 | this.Way = way; 35 | } 36 | 37 | public int Quantity { get; private set; } 38 | 39 | public decimal Price { get; private set; } 40 | 41 | public InvestorWay Way { get; private set; } 42 | 43 | public override string ToString() 44 | { 45 | return String.Format("Instruction executed: Way: {0} - Quantity: {1} - Price: {2}", this.Way, this.Quantity, this.Price); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Investors/InstructionFailedDto.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Infra 23 | { 24 | public class InstructionFailedDto 25 | { 26 | public InstructionFailedDto(string reason) 27 | { 28 | this.Reason = reason; 29 | } 30 | 31 | public string Reason { get; private set; } 32 | } 33 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Investors/InvestorInstructionDto.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Infra 23 | { 24 | using System; 25 | 26 | /// 27 | /// Data Transfer Object for Investor Instruction. 28 | /// 29 | public class InvestorInstructionDto 30 | { 31 | public InvestorInstructionDto(Way way, int quantity, decimal price, bool allowPartialExecution = false, DateTime? goodTill = null) : this(new InvestorInstructionIdentifierDto(), way, quantity, price, allowPartialExecution, goodTill) 32 | { 33 | } 34 | 35 | public InvestorInstructionDto(InvestorInstructionIdentifierDto uniqueIdentifier, Way way, int quantity, decimal price, bool allowPartialExecution = false, DateTime? goodTill = null) 36 | { 37 | this.UniqueIdentifier = uniqueIdentifier; 38 | this.Way = way; 39 | this.Quantity = quantity; 40 | this.Price = price; 41 | this.AllowPartialExecution = allowPartialExecution; 42 | this.GoodTill = goodTill; 43 | } 44 | 45 | public InvestorInstructionIdentifierDto UniqueIdentifier { get; private set; } 46 | 47 | /// 48 | /// Gets the way to be used for the Instruction (Buy/Sell). 49 | /// 50 | /// 51 | /// The way to be used for the Instruction (Buy/Sell). 52 | /// 53 | public Way Way { get; private set; } 54 | 55 | /// 56 | /// Gets the quantity to be bought or sell. 57 | /// 58 | /// 59 | /// The quantity to be bought or sell. 60 | /// 61 | public int Quantity { get; private set; } 62 | 63 | /// 64 | /// Gets the price we are looking for the execution. 65 | /// 66 | /// 67 | /// The price we are looking for the execution. 68 | /// 69 | public decimal Price { get; private set; } 70 | 71 | public bool AllowPartialExecution { get; private set; } 72 | 73 | public DateTime? GoodTill { get; private set; } 74 | 75 | #region Unicity and Identity 76 | 77 | private bool Equals(InvestorInstructionDto other) 78 | { 79 | return object.Equals(this.UniqueIdentifier, other.UniqueIdentifier) && this.Way == other.Way && this.Quantity == other.Quantity && this.Price == other.Price && this.AllowPartialExecution == other.AllowPartialExecution && this.GoodTill.Equals(other.GoodTill); 80 | } 81 | 82 | public override bool Equals(object obj) 83 | { 84 | if (ReferenceEquals(null, obj)) 85 | { 86 | return false; 87 | } 88 | 89 | if (ReferenceEquals(this, obj)) 90 | { 91 | return true; 92 | } 93 | 94 | if (obj.GetType() != this.GetType()) 95 | { 96 | return false; 97 | } 98 | 99 | return this.Equals((InvestorInstructionDto)obj); 100 | } 101 | 102 | public override int GetHashCode() 103 | { 104 | unchecked 105 | { 106 | var hashCode = (this.UniqueIdentifier != null ? this.UniqueIdentifier.GetHashCode() : 0); 107 | hashCode = (hashCode * 397) ^ (int)this.Way; 108 | hashCode = (hashCode * 397) ^ this.Quantity; 109 | hashCode = (hashCode * 397) ^ this.Price.GetHashCode(); 110 | hashCode = (hashCode * 397) ^ this.AllowPartialExecution.GetHashCode(); 111 | hashCode = (hashCode * 397) ^ this.GoodTill.GetHashCode(); 112 | return hashCode; 113 | } 114 | } 115 | 116 | public static bool operator ==(InvestorInstructionDto left, InvestorInstructionDto right) 117 | { 118 | return object.Equals(left, right); 119 | } 120 | 121 | public static bool operator !=(InvestorInstructionDto left, InvestorInstructionDto right) 122 | { 123 | return !object.Equals(left, right); 124 | } 125 | 126 | #endregion 127 | 128 | public override string ToString() 129 | { 130 | return string.Format("Investor Instruction DTO: Way: {0} - Quantity: {1} - Price: {2} - AllowPartialExecution: {3} - GoodTill: {4}.", this.Way, this.Quantity, this.Price, this.AllowPartialExecution, this.GoodTill); 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Investors/InvestorInstructionDtoCallBacks.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Infra 23 | { 24 | using System; 25 | 26 | using SimpleOrderRouting.Investors; 27 | using SimpleOrderRouting.Markets.Orders; 28 | 29 | /// 30 | /// Adapts callbacks from the domain model to the InvestorInstruction infra one. 31 | /// 32 | public class InvestorInstructionDtoCallBacks 33 | { 34 | private readonly Action instructionExecutedCallback; 35 | 36 | private readonly Action instructionFailedCallback; 37 | 38 | public InvestorInstructionDtoCallBacks(Action instructionExecutedCallback, Action instructionFailedCallback) 39 | { 40 | this.instructionExecutedCallback = instructionExecutedCallback; 41 | this.instructionFailedCallback = instructionFailedCallback; 42 | } 43 | 44 | public void ExecutedCallback(InvestorInstructionExecutedEventArgs args) 45 | { 46 | // Adapts to the inside (domain) model to the outside one (investor) 47 | var investorWay = (args.Way == Way.Buy) ? InvestorWay.Buy : InvestorWay.Sell; 48 | var instructionExecutedArgs = new InstructionExecutedDto(investorWay, args.Price, args.Quantity); 49 | this.instructionExecutedCallback(instructionExecutedArgs); 50 | } 51 | 52 | public void FailedCallbacks(string reason) 53 | { 54 | // Adapts to the inside (domain) model to the outside one 55 | var instructionFailedArgs = new InstructionFailedDto(reason); 56 | this.instructionFailedCallback(instructionFailedArgs); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Investors/InvestorInstructionIdentifierDto.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Infra 23 | { 24 | using System.Threading; 25 | 26 | /// 27 | /// Unique Identifier of an Investor instruction DTO. 28 | /// 29 | public class InvestorInstructionIdentifierDto 30 | { 31 | /// 32 | /// Initializes a new instance of the class. 33 | /// 34 | public InvestorInstructionIdentifierDto() 35 | { 36 | this.Value = Interlocked.Increment(ref nextValue); 37 | } 38 | 39 | private bool Equals(InvestorInstructionIdentifierDto other) 40 | { 41 | return this.Value == other.Value; 42 | } 43 | 44 | public override bool Equals(object obj) 45 | { 46 | if (ReferenceEquals(null, obj)) 47 | { 48 | return false; 49 | } 50 | 51 | if (ReferenceEquals(this, obj)) 52 | { 53 | return true; 54 | } 55 | 56 | if (obj.GetType() != this.GetType()) 57 | { 58 | return false; 59 | } 60 | 61 | return this.Equals((InvestorInstructionIdentifierDto)obj); 62 | } 63 | 64 | public override int GetHashCode() 65 | { 66 | return this.Value.GetHashCode(); 67 | } 68 | 69 | public static bool operator ==(InvestorInstructionIdentifierDto left, InvestorInstructionIdentifierDto right) 70 | { 71 | return object.Equals(left, right); 72 | } 73 | 74 | public static bool operator !=(InvestorInstructionIdentifierDto left, InvestorInstructionIdentifierDto right) 75 | { 76 | return !object.Equals(left, right); 77 | } 78 | 79 | private static long nextValue; 80 | 81 | public long Value { get; private set; } 82 | } 83 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Investors/InvestorInstructionUpdatedDto.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Infra 23 | { 24 | using System; 25 | 26 | using SimpleOrderRouting.Investors; 27 | 28 | /// 29 | /// Data transfer Object to interact with an Investor. 30 | /// 31 | public class InvestorInstructionUpdatedDto : EventArgs 32 | { 33 | public InvestorInstructionUpdatedDto(InvestorInstructionIdentifierDto identifierDto, InvestorInstructionStatus status) 34 | { 35 | this.IdentifierDto = identifierDto; 36 | this.Status = status; 37 | } 38 | 39 | public InvestorInstructionIdentifierDto IdentifierDto { get; set; } 40 | 41 | public InvestorInstructionStatus Status { get; set; } 42 | } 43 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Investors/InvestorInstructionsAdapter.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Infra 23 | { 24 | using System; 25 | 26 | using SimpleOrderRouting.Investors; 27 | 28 | /// 29 | /// External API for the Smart Order Routing service. Aggregates all instruction events. 30 | /// (Hexagonal) Adapter from the infrastructure code to the domain code and vice-versa. 31 | /// 32 | public class InvestorInstructionsAdapter 33 | { 34 | private readonly IHandleInvestorInstructions sor; 35 | 36 | /// 37 | /// Initializes a new instance of the class. 38 | /// 39 | /// The SOR entry point. 40 | public InvestorInstructionsAdapter(IHandleInvestorInstructions sor) 41 | { 42 | this.sor = sor; 43 | } 44 | 45 | // TODO: expose some infra callbacks instead of the domain one 46 | public void Route(InvestorInstructionDto investorInstructionDto, Action instructionExecutedCallback, Action instructionFailedCallback) 47 | { 48 | // Maps the DTO model to the domain one 49 | var investorIntruction = new InvestorInstruction(investorInstructionDto.UniqueIdentifier.Value, investorInstructionDto.Way, investorInstructionDto.Quantity, investorInstructionDto.Price, investorInstructionDto.AllowPartialExecution, investorInstructionDto.GoodTill); 50 | var dtoCallBacks = new InvestorInstructionDtoCallBacks(instructionExecutedCallback, instructionFailedCallback); 51 | 52 | this.sor.Route(investorIntruction, dtoCallBacks.ExecutedCallback, dtoCallBacks.FailedCallbacks); 53 | 54 | // TODO: cleanup the dtoCallback resource 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Investors/Way.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Infra 23 | { 24 | /// 25 | /// Sell or Buy way for Orders. 26 | /// 27 | public enum InvestorWay 28 | { 29 | /// 30 | /// The Buy way. 31 | /// 32 | Buy, 33 | 34 | /// 35 | /// The Sell way. 36 | /// 37 | Sell 38 | } 39 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Markets/LimitOrderAdapter.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Infra 23 | { 24 | using OtherTeam.StandardizedMarketGatewayAPI; 25 | 26 | /// 27 | /// Adapts LimitOrder between the SOR and the external market gateway models. 28 | /// 29 | public class LimitOrderAdapter : OrderAdapter 30 | { 31 | private readonly ApiLimitOrder apiLimitOrder; 32 | 33 | public LimitOrderAdapter(ApiMarketGateway marketGateway, ApiLimitOrder apiLimitOrder) 34 | : base(marketGateway, apiLimitOrder) 35 | { 36 | this.apiLimitOrder = apiLimitOrder; 37 | } 38 | 39 | public override void Send() 40 | { 41 | this.MarketGateway.Send(this.apiLimitOrder); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Markets/MarketDataAdapter.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Infra 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | using OtherTeam.StandardizedMarketGatewayAPI; 8 | 9 | using SimpleOrderRouting.Markets.Feeds; 10 | 11 | public sealed class MarketDataAdapter 12 | { 13 | private readonly IReadOnlyDictionary gateways; 14 | 15 | public MarketDataAdapter(IReadOnlyDictionary gateways) 16 | { 17 | this.gateways = gateways; 18 | foreach (var marketGateway in this.gateways.Values) 19 | { 20 | marketGateway.MarketDataUpdated += marketGateway_MarketDataUpdated; 21 | } 22 | } 23 | 24 | void marketGateway_MarketDataUpdated(object sender, ApiMarketDataUpdateEventArgs args) 25 | { 26 | // Adapts the external API feed format to the SOR domain format 27 | var marketDataUpdatedArgs = new MarketDataUpdatedArgs(args.OriginMarketName, args.MarketPrice, args.QuantityOnTheMarket); 28 | this.RaiseMarketDataUpdate(marketDataUpdatedArgs); 29 | } 30 | 31 | public event EventHandler InstrumentMarketDataUpdated; 32 | 33 | public void Subscribe(string marketName) 34 | { 35 | var internalMarket = this.gateways.First(m => m.Key == marketName).Value; 36 | 37 | // Raise the first event 38 | var marketDataUpdatedArgs = new MarketDataUpdatedArgs(internalMarket.MarketName, internalMarket.SellPrice, internalMarket.SellQuantity); 39 | 40 | this.RaiseMarketDataUpdate(marketDataUpdatedArgs); 41 | } 42 | 43 | private void RaiseMarketDataUpdate(MarketDataUpdatedArgs args) 44 | { 45 | var onInstrumentMarketDataUpdated = this.InstrumentMarketDataUpdated; 46 | if (onInstrumentMarketDataUpdated != null) 47 | { 48 | onInstrumentMarketDataUpdated(this, args); 49 | } 50 | } 51 | 52 | } 53 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Markets/MarketOrderAdapter.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Infra 23 | { 24 | using OtherTeam.StandardizedMarketGatewayAPI; 25 | 26 | /// 27 | /// Adapts MarketOrder between the SOR and the external market gateway models. 28 | /// 29 | public class MarketOrderAdapter : OrderAdapter 30 | { 31 | private readonly ApiMarketOrder apiMarketOrder; 32 | 33 | public MarketOrderAdapter(ApiMarketGateway marketGateway, ApiMarketOrder apiMarketOrder) 34 | : base(marketGateway, apiMarketOrder) 35 | { 36 | this.apiMarketOrder = apiMarketOrder; 37 | } 38 | 39 | public override void Send() 40 | { 41 | this.MarketGateway.Send(this.apiMarketOrder); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Markets/OrderAdapter.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Infra 23 | { 24 | using System; 25 | 26 | using OtherTeam.StandardizedMarketGatewayAPI; 27 | 28 | using SimpleOrderRouting.Markets.Orders; 29 | 30 | /// 31 | /// Base class for the and the . 32 | /// 33 | public abstract class OrderAdapter : IOrder 34 | { 35 | protected readonly ApiMarketGateway MarketGateway; 36 | 37 | private readonly ApiOrder apiOrder; 38 | 39 | protected OrderAdapter(ApiMarketGateway marketGateway, ApiOrder apiOrder) 40 | { 41 | this.apiOrder = apiOrder; 42 | this.MarketGateway = marketGateway; 43 | } 44 | 45 | public event EventHandler OrderExecuted; 46 | 47 | public event EventHandler OrderFailed; 48 | 49 | public Way Way 50 | { 51 | get 52 | { 53 | return (this.apiOrder.Way == ApiMarketWay.Sell) ? Way.Sell : Way.Buy; 54 | } 55 | } 56 | 57 | public int Quantity 58 | { 59 | get 60 | { 61 | return this.apiOrder.Quantity; 62 | } 63 | } 64 | 65 | public bool AllowPartialExecution 66 | { 67 | get 68 | { 69 | return false; 70 | } 71 | } 72 | 73 | public abstract void Send(); 74 | } 75 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Markets/OrderRoutingAdapter.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Infra 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | using OtherTeam.StandardizedMarketGatewayAPI; 7 | 8 | using SimpleOrderRouting.Markets.Orders; 9 | 10 | public sealed class OrderRoutingAdapter : ICanRouteOrders 11 | { 12 | private IReadOnlyDictionary gateways; 13 | 14 | public OrderRoutingAdapter(IReadOnlyDictionary gateways) 15 | { 16 | this.gateways = gateways; 17 | } 18 | 19 | public event EventHandler OrderExecuted; 20 | 21 | public event EventHandler OrderFailed; 22 | 23 | 24 | public IOrder CreateMarketOrder(OrderDescription orderDescription) 25 | { 26 | // Adapts from the SOR model to the external market gateway one 27 | var marketGateway = this.gateways[orderDescription.TargetMarketName]; 28 | 29 | ApiMarketWay apiMarketWay = (orderDescription.OrderWay == Way.Sell) ? ApiMarketWay.Sell : ApiMarketWay.Buy; 30 | ApiMarketOrder apiMarketOrder = marketGateway.CreateMarketOrder(apiMarketWay, orderDescription.Quantity); 31 | 32 | return new MarketOrderAdapter(marketGateway, apiMarketOrder); 33 | } 34 | 35 | public IOrder CreateLimitOrder(OrderDescription orderDescription) 36 | { 37 | var marketGateway = this.gateways[orderDescription.TargetMarketName]; 38 | ApiMarketWay apiMarketWay = (orderDescription.OrderWay == Way.Sell) ? ApiMarketWay.Sell : ApiMarketWay.Buy; 39 | ApiLimitOrder apiLimitOrder = marketGateway.CreateLimitOrder(apiMarketWay, orderDescription.Quantity, orderDescription.OrderPrice, orderDescription.AllowPartialExecution); 40 | 41 | return new LimitOrderAdapter(marketGateway, apiLimitOrder); 42 | } 43 | 44 | public void Route(OrderBasket basketOrder) 45 | { 46 | basketOrder.Send(); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: Ozgur DEVELIOGLU (@Zgurrr), Cyrille DUPUYDAUBY 4 | // (@Cyrdup), Tomasz JASKULA (@tjaskula), Thomas PIERRAIN (@tpierrain) 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // -------------------------------------------------------------------------------------------------------------------- 16 | 17 | using System.Reflection; 18 | using System.Runtime.InteropServices; 19 | 20 | // General Information about an assembly is controlled through the following 21 | // set of attributes. Change these attribute values to modify the information 22 | // associated with an assembly. 23 | [assembly: AssemblyTitle("SimpleOrderRouter")] 24 | [assembly: AssemblyDescription("")] 25 | [assembly: AssemblyConfiguration("")] 26 | [assembly: AssemblyCompany("")] 27 | [assembly: AssemblyProduct("SimpleOrderRouter")] 28 | [assembly: AssemblyCopyright("Copyright © 2014")] 29 | [assembly: AssemblyTrademark("")] 30 | [assembly: AssemblyCulture("")] 31 | 32 | // Setting ComVisible to false makes the types in this assembly not visible 33 | // to COM components. If you need to access a type in this assembly from 34 | // COM, set the ComVisible attribute to true on that type. 35 | [assembly: ComVisible(false)] 36 | 37 | // The following GUID is for the ID of the typelib if this project is exposed to COM 38 | [assembly: Guid("b040dd8e-8cb3-42c3-a546-5e9501781325")] 39 | 40 | // Version information for an assembly consists of the following four values: 41 | // 42 | // Major Version 43 | // Minor Version 44 | // Build Number 45 | // Revision 46 | // 47 | // You can specify all the values or you can default the Build and Revision Numbers 48 | // by using the '*' as shown below: 49 | // [assembly: AssemblyVersion("1.0.*")] 50 | [assembly: AssemblyVersion("1.0.0.0")] 51 | [assembly: AssemblyFileVersion("1.0.0.0")] 52 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/Settings.StyleCop: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | awaitable 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | True 13 | 14 | 15 | 16 | 17 | True 18 | 19 | 20 | 21 | 22 | True 23 | 24 | 25 | 26 | 27 | True 28 | 29 | 30 | 31 | 32 | True 33 | 34 | 35 | 36 | 37 | True 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/SimpleOrderRouting.Infra.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {00DD3731-E815-4770-BE17-4F17BFEC4171} 8 | Library 9 | Properties 10 | SimpleOrderRouting.Infra 11 | SimpleOrderRouting.Infra 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | {fe2d8118-afd3-4005-a6d5-c1d240dad3e4} 63 | OtherTeam.StandardizedMarketGatewayAPI 64 | 65 | 66 | {4F66C7D2-8CBD-4280-9A2D-6555E276C6A7} 67 | SimpleOrderRouting.Domain 68 | 69 | 70 | 71 | 78 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Infra/SimpleOrderRouting.Infra.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | True 5 | True -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Tests/Infra/ApiMarketGatewayTests.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | namespace SimpleOrderRouting.Tests.Infra 22 | { 23 | using NFluent; 24 | 25 | using NUnit.Framework; 26 | 27 | using OtherTeam.StandardizedMarketGatewayAPI; 28 | 29 | public class ApiMarketGatewayTests 30 | { 31 | [Test] 32 | public void Should_decrease_available_quantity_for_the_market_when_an_order_is_sent() 33 | { 34 | var marketGateway = new ApiMarketGateway(marketName: "euronext", sellQuantity: 50, sellPrice: 100M); 35 | 36 | var order = marketGateway.CreateMarketOrder(ApiMarketWay.Buy, quantity: 10); 37 | marketGateway.Send(order); 38 | 39 | Check.That(marketGateway.SellQuantity).IsEqualTo(40); 40 | } 41 | 42 | [Test] 43 | public void Should_failed_to_execute_order_when_quantity_is_excessive() 44 | { 45 | var marketGateway = new ApiMarketGateway(marketName: "euronext", sellQuantity: 50, sellPrice: 100M); 46 | 47 | var order = marketGateway.CreateMarketOrder(ApiMarketWay.Buy, quantity: 100); 48 | 49 | bool failed = false; 50 | string failureReason = null; 51 | 52 | marketGateway.OrderFailed += (s, failedEventArgs) => 53 | { 54 | failed = true; 55 | failureReason = failedEventArgs.FailureCause; 56 | }; 57 | 58 | marketGateway.Send(order); 59 | 60 | Check.That(failed).IsTrue(); 61 | Check.That(failureReason).IsEqualTo("Excessive quantity!"); 62 | } 63 | 64 | [Test] 65 | public void Should_Notify_MarketOrder_execution() 66 | { 67 | var marketGateway = new ApiMarketGateway(marketName: "euronext", sellQuantity: 50, sellPrice: 100M); 68 | 69 | var executed = false; 70 | var order = marketGateway.CreateMarketOrder(ApiMarketWay.Buy, quantity: 10); 71 | 72 | marketGateway.OrderExecuted += (s, a) => executed = true; 73 | marketGateway.Send(order); 74 | 75 | Check.That(executed).IsTrue(); 76 | Check.That(marketGateway.SellQuantity).IsEqualTo(40); 77 | } 78 | 79 | [Test] 80 | public void Should_Notify_LimitOrder_execution() 81 | { 82 | var marketGateway = new ApiMarketGateway(marketName: "euronext", sellQuantity: 50, sellPrice: 100M); 83 | 84 | var executed = false; 85 | var order = marketGateway.CreateLimitOrder(ApiMarketWay.Buy, price: 100M, quantity: 10, allowPartial: false); 86 | 87 | marketGateway.OrderExecuted += (s, a) => executed = true; 88 | marketGateway.Send(order); 89 | 90 | Check.That(executed).IsTrue(); 91 | Check.That(marketGateway.SellQuantity).IsEqualTo(40); 92 | } 93 | 94 | [Test] 95 | public void Should_not_execute_LimitOrder_when_price_is_too_high() 96 | { 97 | var marketGateway = new ApiMarketGateway(marketName: "euronext", sellQuantity: 50, sellPrice: 100M); 98 | 99 | var executed = false; 100 | bool failed = false; 101 | string failureReason = null; 102 | var order = marketGateway.CreateLimitOrder(ApiMarketWay.Buy, price: 101M, quantity: 10, allowPartial: false); 103 | 104 | marketGateway.OrderExecuted += (s, a) => executed = true; 105 | marketGateway.OrderFailed += (s, failedEventArgs) => 106 | { 107 | failed = true; 108 | failureReason = failedEventArgs.FailureCause; 109 | }; 110 | marketGateway.Send(order); 111 | 112 | Check.That(executed).IsFalse(); 113 | Check.That(failed).IsTrue(); 114 | Check.That(failureReason).IsEqualTo("Invalid price"); 115 | Check.That(marketGateway.SellQuantity).IsEqualTo(50); 116 | } 117 | 118 | [Test] 119 | public void Should_support_partial_execution_for_LimitOrder() 120 | { 121 | var marketGateway = new ApiMarketGateway(marketName: "euronext", sellQuantity: 50, sellPrice: 100M); 122 | 123 | var executed = false; 124 | var order = marketGateway.CreateLimitOrder(ApiMarketWay.Buy, price: 100M, quantity: 110, allowPartial: true); 125 | 126 | var execQuantity = 0; 127 | marketGateway.OrderExecuted += (s, a) => 128 | { 129 | executed = true; 130 | execQuantity = a.Quantity; 131 | }; 132 | marketGateway.Send(order); 133 | 134 | Check.That(execQuantity).IsEqualTo(50); 135 | Check.That(executed).IsTrue(); 136 | Check.That(marketGateway.SellQuantity).IsEqualTo(0); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Tests/Infra/HarnessTests.cs: -------------------------------------------------------------------------------- 1 | //// -------------------------------------------------------------------------------------------------------------------- 2 | //// 3 | //// Copyright 2014 The Lunch-Box mob: 4 | //// Ozgur DEVELIOGLU (@Zgurrr) 5 | //// Cyrille DUPUYDAUBY (@Cyrdup) 6 | //// Tomasz JASKULA (@tjaskula) 7 | //// Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | //// Thomas PIERRAIN (@tpierrain) 9 | //// 10 | //// Licensed under the Apache License, Version 2.0 (the "License"); 11 | //// you may not use this file except in compliance with the License. 12 | //// You may obtain a copy of the License at 13 | //// http://www.apache.org/licenses/LICENSE-2.0 14 | //// Unless required by applicable law or agreed to in writing, software 15 | //// distributed under the License is distributed on an "AS IS" BASIS, 16 | //// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | //// See the License for the specific language governing permissions and 18 | //// limitations under the License. 19 | //// 20 | //// -------------------------------------------------------------------------------------------------------------------- 21 | //namespace SimpleOrderRouting.Tests 22 | //{ 23 | // using NFluent; 24 | // using Xunit; 25 | 26 | // public class HarnessTests 27 | // { 28 | // [Fact] 29 | // public void Should_return_a_latency() 30 | // { 31 | // var runner = new SorTestHarness(); 32 | // runner.Run(); 33 | 34 | // Check.That(runner.AverageLatency).Not.IsNegative(); 35 | // } 36 | 37 | // } 38 | //} -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Tests/Infra/InvestorInstructionDtoTests.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Tests.Infra 23 | { 24 | using System; 25 | using System.Collections.Generic; 26 | 27 | using NFluent; 28 | 29 | using NUnit.Framework; 30 | 31 | using SimpleOrderRouting.Infra; 32 | using SimpleOrderRouting.Investors; 33 | 34 | public class InvestorInstructionDtoTests 35 | { 36 | [Test] 37 | public void Should_rely_on_values_for_equality() 38 | { 39 | var investorInstructionIdentifier = 42; 40 | const Way Way = Way.Buy; 41 | var quantity = 1; 42 | var price = 23.3M; 43 | var allowPartialExecution = true; 44 | var goodTill = DateTime.Now; 45 | 46 | var dtoIdentifier = new InvestorInstructionIdentifierDto(); 47 | var firstInstruction = new InvestorInstructionDto(dtoIdentifier, Way, quantity, price, allowPartialExecution, goodTill); 48 | var secondIdenticalInstruction = new InvestorInstructionDto(dtoIdentifier, Way, quantity, price, allowPartialExecution, goodTill); 49 | 50 | Check.That(firstInstruction).IsEqualTo(secondIdenticalInstruction); 51 | 52 | allowPartialExecution = false; 53 | var slightlyDifferentInstruction = new InvestorInstruction(investorInstructionIdentifier, Way, quantity, price, allowPartialExecution, goodTill); 54 | Check.That(slightlyDifferentInstruction).IsNotEqualTo(firstInstruction); 55 | } 56 | 57 | [Test] 58 | public void Should_rely_on_values_for_unicity() 59 | { 60 | var goodTill = DateTime.Now; 61 | var dtoIdentifier = new InvestorInstructionIdentifierDto(); 62 | 63 | var instruction = new InvestorInstructionDto(dtoIdentifier, Way.Buy, 1, 1.1M, true, goodTill); 64 | var identicalInstruction = new InvestorInstructionDto(dtoIdentifier, Way.Buy, 1, 1.1M, true, goodTill); 65 | var dictionary = new Dictionary(); 66 | dictionary[instruction] = 2; 67 | dictionary[identicalInstruction] = 3; 68 | 69 | Check.That(dictionary[instruction]).IsEqualTo(3); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Tests/Infra/SorTestHarness.cs: -------------------------------------------------------------------------------- 1 | //// -------------------------------------------------------------------------------------------------------------------- 2 | //// 3 | //// Copyright 2014 The Lunch-Box mob: 4 | //// Ozgur DEVELIOGLU (@Zgurrr) 5 | //// Cyrille DUPUYDAUBY (@Cyrdup) 6 | //// Tomasz JASKULA (@tjaskula) 7 | //// Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | //// Thomas PIERRAIN (@tpierrain) 9 | //// 10 | //// Licensed under the Apache License, Version 2.0 (the "License"); 11 | //// you may not use this file except in compliance with the License. 12 | //// You may obtain a copy of the License at 13 | //// http://www.apache.org/licenses/LICENSE-2.0 14 | //// Unless required by applicable law or agreed to in writing, software 15 | //// distributed under the License is distributed on an "AS IS" BASIS, 16 | //// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | //// See the License for the specific language governing permissions and 18 | //// limitations under the License. 19 | //// 20 | //// -------------------------------------------------------------------------------------------------------------------- 21 | //namespace SimpleOrderRouting.Tests 22 | //{ 23 | // using System.Collections.Generic; 24 | // using System.Diagnostics; 25 | // using System.Threading; 26 | 27 | // using SimpleOrderRouting.Infra; 28 | // using SimpleOrderRouting.Investors; 29 | // using SimpleOrderRouting.Markets; 30 | // using SimpleOrderRouting.Markets.Orders; 31 | // using SimpleOrderRouting.Tests.TestHelpers; 32 | 33 | // public class SorTestHarness 34 | // { 35 | // private InvestorInstructionDto investorInstructionDto; 36 | 37 | // private readonly object synchro = new object(); 38 | 39 | // private bool done = false; 40 | 41 | // private InvestorInstructionIdentifierDto instructionIdentifier; 42 | 43 | // public void Run() 44 | // { 45 | // // Build our hexagon (3 steps) 46 | 47 | // // 1. Builds the runtime dependencies needed for our domain to work with (through DIP) 48 | // var markets = BuildMarketVenues(); 49 | // var marketDataProvider = new MarketDataProvider(markets); 50 | // var marketProvider = new MarketProvider(markets); 51 | 52 | // // 2. Instantiates our domain entry point with its runtime dependencies 53 | // var sor = new SmartOrderRoutingEngine(marketProvider, null, marketDataProvider); 54 | 55 | // // 3. Instantiates the adapter(s) we will use to interact with our domain 56 | // var instructionsAdapter = new InvestorInstructionsAdapter(sor); 57 | 58 | // // Prepare the adapter to do some work 59 | // instructionsAdapter.InstructionUpdated += this.ServiceOnInstructionUpdated; 60 | // var identifier = InvestorInstructionIdentifierFactory.RequestUniqueIdentifier(); 61 | // this.instructionIdentifier = identifier; //adapter.RequestUniqueIdentifier(); 62 | 63 | // // build demo order 64 | // this.investorInstructionDto = new InvestorInstructionDto(identifier, Way.Buy, 10, 100M, true, null); 65 | 66 | // var stopWatch = new Stopwatch(); 67 | 68 | // // sends the instruction 69 | // stopWatch.Start(); 70 | // // Subscribes to the instruction's events 71 | // OrderExecutedEventArgs orderExecutedEventArgs = null; 72 | // string failureReason = null; 73 | // instructionsAdapter.Route(this.investorInstructionDto, (args) => { orderExecutedEventArgs = args; }, (args) => { failureReason = args; }); 74 | // instructionsAdapter.Route(this.investorInstructionDto); 75 | 76 | // // wait for the exit condition 77 | // lock (this.synchro) 78 | // { 79 | // if (this.done == false) 80 | // { 81 | // Monitor.Wait(this.synchro, 500); 82 | // } 83 | // } 84 | 85 | // stopWatch.Stop(); 86 | 87 | // if (this.done) 88 | // { 89 | // this.AverageLatency = stopWatch.ElapsedMilliseconds; 90 | // } 91 | 92 | // } 93 | 94 | // private void ServiceOnInstructionUpdated(object sender, InvestorInstructionUpdatedDto investorInstructionUpdatedDto) 95 | // { 96 | // if (investorInstructionUpdatedDto.IdentifierDto == this.instructionIdentifier) 97 | // { 98 | // if (investorInstructionUpdatedDto.Status == InvestorInstructionStatus.PartiallyExecuted) 99 | // { 100 | // return; 101 | // } 102 | // lock (this.synchro) 103 | // { 104 | // this.done = true; 105 | // Monitor.PulseAll(this.synchro); 106 | // } 107 | // } 108 | // } 109 | 110 | // private static IEnumerable BuildMarketVenues() 111 | // { 112 | // var marketA = new Market 113 | // { 114 | // SellQuantity = 150, 115 | // SellPrice = 100M, 116 | // }; 117 | 118 | // var marketB = new Market 119 | // { 120 | // SellQuantity = 55, 121 | // SellPrice = 101M, 122 | // }; 123 | 124 | // var markets = new[] { marketA, marketB }; 125 | // return markets; 126 | // } 127 | 128 | // public double AverageLatency { get; set; } 129 | // } 130 | //} -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Tests/InvestorInstructionTests.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Tests 23 | { 24 | using System; 25 | using System.Collections.Generic; 26 | 27 | using NFluent; 28 | 29 | using NUnit.Framework; 30 | 31 | using SimpleOrderRouting.Investors; 32 | 33 | public class InvestorInstructionTests 34 | { 35 | [Test] 36 | public void Should_rely_on_values_for_equality() 37 | { 38 | var investorInstructionIdentifier = 42; 39 | const Way Way = Way.Buy; 40 | const int quantity = 1; 41 | var price = 23.3M; 42 | var allowPartialExecution = true; 43 | var goodTill = DateTime.Now; 44 | 45 | var firstInstruction = new InvestorInstruction(investorInstructionIdentifier, Way, quantity, price, allowPartialExecution, goodTill); 46 | var secondIdenticalInstruction = new InvestorInstruction(investorInstructionIdentifier, Way, quantity, price, allowPartialExecution, goodTill); 47 | 48 | Check.That(firstInstruction).IsEqualTo(secondIdenticalInstruction); 49 | 50 | allowPartialExecution = false; 51 | var slightlyDifferentInstruction = new InvestorInstruction(investorInstructionIdentifier, Way, quantity, price, allowPartialExecution, goodTill); 52 | Check.That(slightlyDifferentInstruction).IsNotEqualTo(firstInstruction); 53 | } 54 | 55 | [Test] 56 | public void Should_rely_on_values_for_unicity() 57 | { 58 | var goodTill = DateTime.Now; 59 | var instruction = new InvestorInstruction(1, Way.Buy, 1, 1.1M, true, goodTill); 60 | var identicalInstruction = new InvestorInstruction(1, Way.Buy, 1, 1.1M, true, goodTill); 61 | var dictionary = new Dictionary(); 62 | dictionary[instruction] = 2; 63 | dictionary[identicalInstruction] = 3; 64 | 65 | Check.That(dictionary[instruction]).IsEqualTo(3); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Tests/MarketSweepSolverTests.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Tests 23 | { 24 | using System; 25 | 26 | using NFluent; 27 | 28 | using NUnit.Framework; 29 | 30 | using OtherTeam.StandardizedMarketGatewayAPI; 31 | 32 | using SimpleOrderRouting.Infra; 33 | using SimpleOrderRouting.Investors; 34 | using SimpleOrderRouting.Markets; 35 | using SimpleOrderRouting.SolvingStrategies; 36 | 37 | public class MarketSweepSolverTests 38 | { 39 | [Test] 40 | public void Should_Solve_with_2_markets_when_asked_quantity_is_odd() 41 | { 42 | var marketA = new ApiMarketGateway("NYSE (New York)", sellQuantity: 50, sellPrice: 100M); 43 | var rejectingMarket = new ApiMarketGateway("CME (Chicago)", sellQuantity: 50, sellPrice: 100M, orderPredicate: _ => false); 44 | var marketsInvolved = new[] { marketA, rejectingMarket }; 45 | var marketGatewayAdapter = new MarketsAdapter(marketsInvolved); 46 | 47 | var investorInstruction = new InvestorInstruction(new InvestorInstructionIdentifierDto().Value, Way.Buy, quantity: 50, price: 100M, goodTill: DateTime.Now.AddMinutes(5)); 48 | var instructionExecutionContext = new InstructionExecutionContext(investorInstruction, args => {}, failure => {}); 49 | 50 | var marketSweepSolver = new MarketSweepSolver(new MarketSnapshotProvider(marketGatewayAdapter.GetAvailableMarketNames(), marketGatewayAdapter)); 51 | var orderBasket = marketSweepSolver.Solve(instructionExecutionContext, marketGatewayAdapter); 52 | 53 | Check.That(orderBasket.OrdersDescriptions.Extracting("Quantity")).ContainsExactly(25, 25); 54 | } 55 | 56 | [Test] 57 | public void Should_Solve_with_2_markets_when_asked_quantity_is_1() 58 | { 59 | var marketA = new ApiMarketGateway("NYSE (New York)", sellQuantity: 50, sellPrice: 100M); 60 | var rejectingMarket = new ApiMarketGateway("CME (Chicago)", sellQuantity: 50, sellPrice: 100M, orderPredicate: _ => false); 61 | var marketsInvolved = new[] { marketA, rejectingMarket }; 62 | var marketGatewayAdapter = new MarketsAdapter(marketsInvolved); 63 | 64 | var investorInstruction = new InvestorInstruction(new InvestorInstructionIdentifierDto().Value, Way.Buy, quantity: 1, price: 100M, goodTill: DateTime.Now.AddMinutes(5)); 65 | var instructionExecutionContext = new InstructionExecutionContext(investorInstruction, args => { }, failure => { }); 66 | 67 | var marketSweepSolver = new MarketSweepSolver(new MarketSnapshotProvider(marketGatewayAdapter.GetAvailableMarketNames(), marketGatewayAdapter)); 68 | var orderBasket = marketSweepSolver.Solve(instructionExecutionContext, marketGatewayAdapter); 69 | 70 | Check.That(orderBasket.OrdersDescriptions.Extracting("Quantity")).ContainsExactly(1); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: Ozgur DEVELIOGLU (@Zgurrr), Cyrille DUPUYDAUBY 4 | // (@Cyrdup), Tomasz JASKULA (@tjaskula), Thomas PIERRAIN (@tpierrain) 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // -------------------------------------------------------------------------------------------------------------------- 16 | 17 | using System.Reflection; 18 | using System.Runtime.InteropServices; 19 | 20 | // General Information about an assembly is controlled through the following 21 | // set of attributes. Change these attribute values to modify the information 22 | // associated with an assembly. 23 | [assembly: AssemblyTitle("SimpleOrderRouter.Tests")] 24 | [assembly: AssemblyDescription("")] 25 | [assembly: AssemblyConfiguration("")] 26 | [assembly: AssemblyCompany("")] 27 | [assembly: AssemblyProduct("SimpleOrderRouter.Tests")] 28 | [assembly: AssemblyCopyright("Copyright © 2014")] 29 | [assembly: AssemblyTrademark("")] 30 | [assembly: AssemblyCulture("")] 31 | 32 | // Setting ComVisible to false makes the types in this assembly not visible 33 | // to COM components. If you need to access a type in this assembly from 34 | // COM, set the ComVisible attribute to true on that type. 35 | [assembly: ComVisible(false)] 36 | 37 | // The following GUID is for the ID of the typelib if this project is exposed to COM 38 | [assembly: Guid("f3230376-e78f-4d20-aa05-dfd71f79e272")] 39 | 40 | // Version information for an assembly consists of the following four values: 41 | // 42 | // Major Version 43 | // Minor Version 44 | // Build Number 45 | // Revision 46 | // 47 | // You can specify all the values or you can default the Build and Revision Numbers 48 | // by using the '*' as shown below: 49 | // [assembly: AssemblyVersion("1.0.*")] 50 | [assembly: AssemblyVersion("1.0.0.0")] 51 | [assembly: AssemblyFileVersion("1.0.0.0")] 52 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Tests/Settings.StyleCop: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | False 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | True 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Tests/SimpleOrderRouting.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {7F099472-E44E-4252-BBB8-633BF48EECBB} 8 | Library 9 | Properties 10 | SimpleOrderRouting.Tests 11 | SimpleOrderRouting.Tests 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\NFluent.1.3.1.0\lib\net40\NFluent.dll 37 | 38 | 39 | ..\packages\NSubstitute.1.7.2.0\lib\NET45\NSubstitute.dll 40 | 41 | 42 | ..\packages\NUnit.3.2.1\lib\net45\nunit.framework.dll 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | {fe2d8118-afd3-4005-a6d5-c1d240dad3e4} 69 | OtherTeam.StandardizedMarketGatewayAPI 70 | 71 | 72 | {4F66C7D2-8CBD-4280-9A2D-6555E276C6A7} 73 | SimpleOrderRouting.Domain 74 | 75 | 76 | {00dd3731-e815-4770-be17-4f17bfec4171} 77 | SimpleOrderRouting.Infra 78 | 79 | 80 | 81 | 82 | 83 | 84 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 85 | 86 | 87 | 88 | 95 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleOrderRouting.Infra", "SimpleOrderRouting.Infra\SimpleOrderRouting.Infra.csproj", "{00DD3731-E815-4770-BE17-4F17BFEC4171}" 5 | EndProject 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{AE7BEF9F-3190-4A0C-AF57-F9B3E844FC01}" 7 | ProjectSection(SolutionItems) = preProject 8 | ..\Backlog.md = ..\Backlog.md 9 | DoD.md = DoD.md 10 | LICENSE.txt = LICENSE.txt 11 | ..\Readme.md = ..\Readme.md 12 | Settings.StyleCop = Settings.StyleCop 13 | EndProjectSection 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleOrderRouting.Tests", "SimpleOrderRouting.Tests\SimpleOrderRouting.Tests.csproj", "{7F099472-E44E-4252-BBB8-633BF48EECBB}" 16 | EndProject 17 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{F7A88DF0-5710-4A1C-9F9B-3D1C36D60186}" 18 | ProjectSection(SolutionItems) = preProject 19 | .nuget\NuGet.Config = .nuget\NuGet.Config 20 | .nuget\NuGet.exe = .nuget\NuGet.exe 21 | .nuget\NuGet.targets = .nuget\NuGet.targets 22 | EndProjectSection 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleOrderRouting.Domain", "SimpleOrderRouting.Domain\SimpleOrderRouting.Domain.csproj", "{4F66C7D2-8CBD-4280-9A2D-6555E276C6A7}" 25 | EndProject 26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OtherTeam.StandardizedMarketGatewayAPI", "OtherTeam.StandardizedMarketGatewayAPI\OtherTeam.StandardizedMarketGatewayAPI.csproj", "{FE2D8118-AFD3-4005-A6D5-C1D240DAD3E4}" 27 | EndProject 28 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleOrderRouting.Console", "SimpleOrderRouting.Console\SimpleOrderRouting.Console.csproj", "{F20EBD6E-C774-4856-91D5-1BA43005513D}" 29 | EndProject 30 | Global 31 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 32 | Debug|Any CPU = Debug|Any CPU 33 | Release|Any CPU = Release|Any CPU 34 | EndGlobalSection 35 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 36 | {00DD3731-E815-4770-BE17-4F17BFEC4171}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {00DD3731-E815-4770-BE17-4F17BFEC4171}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {00DD3731-E815-4770-BE17-4F17BFEC4171}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {00DD3731-E815-4770-BE17-4F17BFEC4171}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {7F099472-E44E-4252-BBB8-633BF48EECBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {7F099472-E44E-4252-BBB8-633BF48EECBB}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {7F099472-E44E-4252-BBB8-633BF48EECBB}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {7F099472-E44E-4252-BBB8-633BF48EECBB}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {4F66C7D2-8CBD-4280-9A2D-6555E276C6A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {4F66C7D2-8CBD-4280-9A2D-6555E276C6A7}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {4F66C7D2-8CBD-4280-9A2D-6555E276C6A7}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {4F66C7D2-8CBD-4280-9A2D-6555E276C6A7}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {FE2D8118-AFD3-4005-A6D5-C1D240DAD3E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {FE2D8118-AFD3-4005-A6D5-C1D240DAD3E4}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {FE2D8118-AFD3-4005-A6D5-C1D240DAD3E4}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {FE2D8118-AFD3-4005-A6D5-C1D240DAD3E4}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {F20EBD6E-C774-4856-91D5-1BA43005513D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {F20EBD6E-C774-4856-91D5-1BA43005513D}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {F20EBD6E-C774-4856-91D5-1BA43005513D}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {F20EBD6E-C774-4856-91D5-1BA43005513D}.Release|Any CPU.Build.0 = Release|Any CPU 56 | EndGlobalSection 57 | GlobalSection(SolutionProperties) = preSolution 58 | HideSolutionNode = FALSE 59 | EndGlobalSection 60 | EndGlobal 61 | -------------------------------------------------------------------------------- /CSharp/SimpleOrderRouting.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | -------------------------------------------------------------------------------------------------------------------- 3 | <copyright file="$FILENAME$" company="LunchBox corp"> 4 | Copyright 2014 The Lunch-Box mob: 5 | Ozgur DEVELIOGLU (@Zgurrr) 6 | Cyrille DUPUYDAUBY (@Cyrdup) 7 | Tomasz JASKULA (@tjaskula) 8 | Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 9 | Thomas PIERRAIN (@tpierrain) 10 | 11 | Licensed under the Apache License, Version 2.0 (the "License"); 12 | you may not use this file except in compliance with the License. 13 | You may obtain a copy of the License at 14 | http://www.apache.org/licenses/LICENSE-2.0 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | </copyright> 21 | -------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /DoD.md: -------------------------------------------------------------------------------- 1 | Definition of Done for the SOR project 2 | ====================================== 3 | 4 | We can push when: 5 | 6 | 1. Test coverage is 100% 7 | 1. No StyleCop issue is detected 8 | 9 | -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Journey1/Adapters.fs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Journey1 2 | 3 | module MarketAdapters = 4 | 5 | open System 6 | open Domain 7 | open Dtos 8 | 9 | let send (investorInstructionDto : InvestorInstructionDto) = 10 | let investorInstruction = dtoToInvestorInstruction investorInstructionDto 11 | () -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Journey1/Adapters.fsi: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Journey1 2 | 3 | module MarketAdapters = 4 | 5 | open Dtos 6 | 7 | val send : investorInstructionDto : InvestorInstructionDto -> unit -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Journey1/Domain.fs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Journey1 2 | 3 | module Domain = 4 | 5 | open System 6 | open Rop 7 | 8 | type Way = 9 | | Buy 10 | | Sell 11 | 12 | type Market = {SellQuantity : int; SellPrice : decimal; TimeSent : int} 13 | 14 | // ------------------------------ 15 | // InvestorInstruction 16 | 17 | type InvestorInstructionId = InvestorInstructionId of int 18 | type InvestorInstruction = {Way : Way; Quantity : int; Price : decimal; AllowPartialExecution : bool; GoodTill : DateTime option} 19 | 20 | // Create a InvestorInstructionId from an int 21 | let createInvestorInstructionId id = 22 | if id < 1 then 23 | fail "InvestorInstructionId must be positive integer" 24 | else 25 | succeed (InvestorInstructionId id) -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Journey1/Domain.fsi: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Journey1 2 | 3 | module Domain = 4 | 5 | open Rop 6 | 7 | type InvestorInstructionId 8 | 9 | val createInvestorInstructionId : id:int -> RopResult -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Journey1/External.fs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Journey1 2 | 3 | module Markets = 4 | 5 | // TODO : This should be declared in an external assembly (we don't owe this code) 6 | type ExternalMarket = {SellQuantity : int; SellPrice : decimal; TimeSent : int} -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Journey1/External.fsi: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Journey1 2 | 3 | module Markets = 4 | 5 | type ExternalMarket -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Journey1/MarketDataAdapter.fs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Journey1.Infrastructure.Adapters 2 | 3 | module Market = 4 | 5 | let getAvailableMarkets marketsOfInterest = 6 | () -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Journey1/Ports.fs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Journey1.Infrastructure 2 | 3 | // This is the simulation of the external port that invokes the internal adatpers of the domain. 4 | // This part is not generaly implemented by us but represents an external framework. 5 | module Ports = 6 | 7 | // In memory port that allows to invoke API from the RPC in memory call. 8 | module InMemory = 9 | 10 | // Entry point of the port where a raw data is received (queue, REST, SOAP, etc.) 11 | let send rawData = 12 | () -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Journey1/SORoutingEngine.fs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Journey1 2 | 3 | module Dtos = 4 | 5 | open System 6 | open Domain 7 | 8 | type WayDto = 9 | | Buy 10 | | Sell 11 | | Uninitialized 12 | 13 | /// Represents a DTO that is exposed to the outside world. 14 | /// This is a regular POCO class which can be null. 15 | /// 16 | /// you have to try hard to make an nullable object in F# 17 | [] 18 | type InvestorInstructionDto() = 19 | member val Id : int = 0 with get, set 20 | member val Way : WayDto = Uninitialized with get, set 21 | member val Quantity : int = 0 with get, set 22 | member val Price : decimal = 0m with get, set 23 | member val AllowPartialExecution : bool = false with get, set 24 | member val GoodTill : Nullable = Nullable() with get, set 25 | 26 | /// Convert a DTO into a domain contact. 27 | /// 28 | /// We MUST handle the possibility of one or more errors 29 | /// because the InvestorInstruction type has stricter constraints than InvestorInstructionDto 30 | /// and the conversion might fail. 31 | /// This is the adapter entry point for converting the external InvestorInstructionDto to the internal domain 32 | let dtoToInvestorInstruction (dto : InvestorInstructionDto) = 33 | if dto = null then 34 | Rop.fail "Investor instruction is required" 35 | else 36 | let idOrError = createInvestorInstructionId dto.Id 37 | Rop.fail "sdsd" 38 | //{Way = Buy; Quantity = 0; Price = 0m; AllowPartialExecution = false} 39 | 40 | module SmartOrderRoutingEngine = 41 | 42 | let route inverstorInstruction = 43 | () -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Journey1/Script.fsx: -------------------------------------------------------------------------------- 1 | // Learn more about F# at http://fsharp.net. See the 'F# Tutorial' project 2 | // for more guidance on F# programming. 3 | 4 | #load "Utilities.fs" 5 | open SimpleOrderRouting.Journey1.Rop 6 | 7 | // Define your library scripting code here 8 | 9 | -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Journey1/SimpleOrderRouting.Journey1.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 2.0 8 | 63815e01-ad47-4d83-98f5-87160a503d02 9 | Library 10 | SimpleOrderRouting.Journey1 11 | SimpleOrderRouting.Journey1 12 | v4.5.1 13 | 4.3.1.0 14 | SimpleOrderRouting.Journey1 15 | 16 | 17 | true 18 | full 19 | false 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | 3 24 | bin\Debug\SimpleOrderRouting.Journey1.XML 25 | 26 | 27 | pdbonly 28 | true 29 | true 30 | bin\Release\ 31 | TRACE 32 | 3 33 | bin\Release\SimpleOrderRouting.Journey1.XML 34 | 35 | 36 | 37 | 38 | True 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 11 59 | 60 | 61 | 62 | 63 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 64 | 65 | 66 | 67 | 68 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 69 | 70 | 71 | 72 | 73 | 80 | -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Journey1/Utilities.fs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Journey1 2 | 3 | module Rop = 4 | 5 | // ============================================== 6 | // This is a utility library for managing Success/Failure results 7 | // 8 | // See http://fsharpforfunandprofit.com/rop 9 | // See https://github.com/swlaschin/Railway-Oriented-Programming-Example 10 | // ============================================== 11 | 12 | /// A Result is a success or failure 13 | /// The Success case has a success value 14 | /// The Failure case has a list of messages 15 | 16 | type RopResult<'TSuccess> = 17 | | Success of 'TSuccess 18 | | Failure of string list 19 | 20 | /// create a Success with no messages 21 | let succeed x = 22 | Success x 23 | 24 | /// create a Failure with a message 25 | let fail msg = 26 | Failure [msg] 27 | 28 | /// given a function wrapped in a result 29 | /// and a value wrapped in a result 30 | /// apply the function to the value only if both are Success 31 | let applyR f result = 32 | match f,result with 33 | | Success f, Success x -> 34 | f x |> Success 35 | | Failure errs, Success _ 36 | | Success _, Failure errs -> 37 | errs |> Failure 38 | | Failure errs1, Failure errs2 -> 39 | errs1 @ errs2 |> Failure 40 | 41 | /// given a function that transforms a value 42 | /// apply it only if the result is on the Success branch 43 | let liftR f result = 44 | let f' = f |> succeed 45 | applyR f' result 46 | 47 | /// given two values wrapped in results apply a function to both 48 | let lift2R f result1 result2 = 49 | let f' = liftR f result1 50 | applyR f' result2 51 | 52 | /// given three values wrapped in results apply a function to all 53 | let lift3R f result1 result2 result3 = 54 | let f' = lift2R f result1 result2 55 | applyR f' result3 -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Tests/MarketTests.fs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Tests 23 | 24 | open Xunit 25 | open FsUnit.Xunit 26 | 27 | module ``Market tests`` = 28 | 29 | [] 30 | let ``Market order should decrease available quantity`` = 31 | () 32 | 33 | 34 | -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Tests/SimpleOrderRouting.Tests.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 2.0 8 | 54d4d857-f008-4817-bfc5-0f3234ff8781 9 | Library 10 | SimpleOrderRouting.Tests 11 | SimpleOrderRouting.Tests 12 | v4.5.1 13 | 4.3.1.0 14 | SimpleOrderRouting.Tests 15 | 16 | 17 | true 18 | full 19 | false 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | 3 24 | bin\Debug\SimpleOrderRouting.Tests.XML 25 | 26 | 27 | pdbonly 28 | true 29 | true 30 | bin\Release\ 31 | TRACE 32 | 3 33 | bin\Release\SimpleOrderRouting.Tests.XML 34 | 35 | 36 | 11 37 | 38 | 39 | 40 | 41 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 42 | 43 | 44 | 45 | 46 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | ..\packages\FsUnit.xUnit.1.3.0.1\Lib\net40\FsUnit.CustomMatchers.dll 61 | True 62 | 63 | 64 | ..\packages\FsUnit.xUnit.1.3.0.1\Lib\net40\FsUnit.Xunit.dll 65 | True 66 | 67 | 68 | 69 | True 70 | 71 | 72 | ..\packages\FsUnit.xUnit.1.3.0.1\Lib\net40\NHamcrest.dll 73 | True 74 | 75 | 76 | 77 | 78 | 79 | ..\packages\xunit.1.9.2\lib\net20\xunit.dll 80 | True 81 | 82 | 83 | 84 | 85 | SimpleOrderRouting.Journey1 86 | {63815e01-ad47-4d83-98f5-87160a503d02} 87 | True 88 | 89 | 90 | 97 | -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Tests/SorAcceptanceTests.fs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // Copyright 2014 The Lunch-Box mob: 4 | // Ozgur DEVELIOGLU (@Zgurrr) 5 | // Cyrille DUPUYDAUBY (@Cyrdup) 6 | // Tomasz JASKULA (@tjaskula) 7 | // Mendel MONTEIRO-BECKERMAN (@MendelMonteiro) 8 | // Thomas PIERRAIN (@tpierrain) 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | // 20 | // -------------------------------------------------------------------------------------------------------------------- 21 | 22 | namespace SimpleOrderRouting.Tests 23 | 24 | open Xunit 25 | open FsUnit.Xunit 26 | 27 | module ``Sor acceptance tests`` = 28 | 29 | [] 30 | let ``External Api visibility tests``() = 31 | true |> should be True 32 | 33 | [] 34 | let ``Should execute "Instruction" When there is enough liquidity on one "Market"``() = 35 | true |> should be True -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Tests/UtilitiesTests.fs: -------------------------------------------------------------------------------- 1 | namespace SimpleOrderRouting.Tests 2 | 3 | open Xunit 4 | open FsUnit.Xunit 5 | open SimpleOrderRouting.Journey1.Rop 6 | 7 | module ``Rop tests`` = 8 | 9 | let failBranch() = 10 | failwith "This branch should not have been called." 11 | 12 | [] 13 | let ``Create a Success with no messages``() = 14 | let result = succeed 10 15 | match result with 16 | | Success v -> v |> should equal 10 17 | | Failure _ -> failBranch() 18 | 19 | [] 20 | let ``Create a Failure with a message``() = 21 | let result = fail "This is a failure" 22 | match result with 23 | | Success _ -> failBranch() 24 | | Failure errors -> errors.[0] |> should equal "This is a failure" 25 | 26 | [] 27 | let ``Apply the function to the value only if both are Success``() = 28 | let success = succeed 10 29 | let intToString i = i.ToString() 30 | let successFunc = succeed intToString 31 | let result = applyR successFunc success 32 | match result with 33 | | Success r -> r |> should equal "10" 34 | | Failure _ -> failBranch() 35 | 36 | [] 37 | let ``Apply returns Failure if value is not a Success``() = 38 | let failure = fail "First error" 39 | let intToString i = i.ToString() 40 | let successFunc = succeed intToString 41 | let result = applyR successFunc failure 42 | match result with 43 | | Success _ -> failBranch() 44 | | Failure errors -> errors.[0] |> should equal "First error" 45 | 46 | [] 47 | let ``Apply returns Failure if function is not a Success``() = 48 | let success = succeed 10 49 | let intToString i = i.ToString() 50 | let failFunc = fail "Function in error" 51 | let result = applyR failFunc success 52 | match result with 53 | | Success _ -> failBranch() 54 | | Failure errors -> errors.[0] |> should equal "Function in error" 55 | 56 | [] 57 | let ``Apply returns Failure if function and value are not a Success``() = 58 | let expectedErrors = ["First error"; "Function in error"] 59 | let failure = fail expectedErrors.[0] 60 | let intToString i = i.ToString() 61 | let failFunc = fail expectedErrors.[1] 62 | let result = applyR failFunc failure 63 | match result with 64 | | Success _ -> failBranch() 65 | | Failure errors -> errors |> List.rev 66 | |> List.iteri (fun i e -> e |> should equal expectedErrors.[i]) 67 | 68 | [] 69 | let ``Litf a function and applies it if the result is on the Success branch``() = 70 | let intToString i = i.ToString() 71 | let value = succeed 10 72 | let result = liftR intToString value 73 | match result with 74 | | Success r -> r |> should equal "10" 75 | | Failure _ -> failBranch() 76 | 77 | [] 78 | let ``Litf a function and not applies it if the result is on the Failure branch``() = 79 | let intToString i = i.ToString() 80 | let value = fail "Failed value" 81 | let result = liftR intToString value 82 | match result with 83 | | Success r -> failBranch() 84 | | Failure errors -> errors.[0] |> should equal "Failed value" 85 | 86 | [] 87 | let ``Litf two functions and applies it if the results are on the Success branch``() = 88 | let intToString i i' = (i * i').ToString() 89 | let value = succeed 10 90 | let value' = succeed 5 91 | let result = lift2R intToString value value' 92 | match result with 93 | | Success r -> r |> should equal "50" 94 | | Failure _ -> failBranch() 95 | 96 | [] 97 | let ``Litf two functions and not applies it if one of the results are on the Failure branch``() = 98 | let intToString i i' = (i * i').ToString() 99 | let value = fail "First value failed" 100 | let value' = succeed 10 101 | let result = lift2R intToString value value' 102 | match result with 103 | | Success _ -> failBranch() 104 | | Failure errors -> errors.[0] |> should equal "First value failed" 105 | 106 | [] 107 | let ``Litf two functions and not applies it if one of the results are on the Failure branch'``() = 108 | let intToString i i' = (i * i').ToString() 109 | let value = succeed 10 110 | let value' = fail "Second value failed" 111 | let result = lift2R intToString value value' 112 | match result with 113 | | Success _ -> failBranch() 114 | | Failure errors -> errors.[0] |> should equal "Second value failed" 115 | 116 | [] 117 | let ``Litf three functions and applies it if the results are on the Success branch``() = 118 | let intToString i i' i'' = (i * i' + i'').ToString() 119 | let value = succeed 10 120 | let value' = succeed 5 121 | let value'' = succeed 2 122 | let result = lift3R intToString value value' value'' 123 | match result with 124 | | Success r -> r |> should equal "52" 125 | | Failure _ -> failBranch() 126 | 127 | [] 128 | let ``Litf three functions and not applies it if one the results are on the Failure branch``() = 129 | let intToString i i' i'' = (i * i' + i'').ToString() 130 | let value = fail "First value failure" 131 | let value' = succeed 5 132 | let value'' = succeed 2 133 | let result = lift3R intToString value value' value'' 134 | match result with 135 | | Success _ -> failBranch() 136 | | Failure errors-> errors.[0] |> should equal "First value failure" 137 | 138 | [] 139 | let ``Litf three functions and not applies it if one the results are on the Failure branch'``() = 140 | let intToString i i' i'' = (i * i' + i'').ToString() 141 | let value = succeed 10 142 | let value' = fail "Second value failure" 143 | let value'' = succeed 2 144 | let result = lift3R intToString value value' value'' 145 | match result with 146 | | Success _ -> failBranch() 147 | | Failure errors-> errors.[0] |> should equal "Second value failure" 148 | 149 | [] 150 | let ``Litf three functions and not applies it if one the results are on the Failure branch''``() = 151 | let intToString i i' i'' = (i * i' + i'').ToString() 152 | let value = succeed 10 153 | let value' = succeed 5 154 | let value'' = fail "Third value failure" 155 | let result = lift3R intToString value value' value'' 156 | match result with 157 | | Success _ -> failBranch() 158 | | Failure errors-> errors.[0] |> should equal "Third value failure" 159 | 160 | [] 161 | let ``Litf three functions and not applies it if one the results are on the Failure branch'''``() = 162 | let expectedErrors = ["First value failure"; "Third value failure"] 163 | let intToString i i' i'' = (i * i' + i'').ToString() 164 | let value = fail expectedErrors.[0] 165 | let value' = succeed 5 166 | let value'' = fail expectedErrors.[1] 167 | let result = lift3R intToString value value' value'' 168 | match result with 169 | | Success _ -> failBranch() 170 | | Failure errors-> errors |> List.iteri (fun i e -> e |> should equal expectedErrors.[i]) -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Tests/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /FSharp/SimpleOrderRouting.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30723.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "SimpleOrderRouting.Journey1", "SimpleOrderRouting.Journey1\SimpleOrderRouting.Journey1.fsproj", "{63815E01-AD47-4D83-98F5-87160A503D02}" 7 | EndProject 8 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "SimpleOrderRouting.Tests", "SimpleOrderRouting.Tests\SimpleOrderRouting.Tests.fsproj", "{54D4D857-F008-4817-BFC5-0F3234FF8781}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {63815E01-AD47-4D83-98F5-87160A503D02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {63815E01-AD47-4D83-98F5-87160A503D02}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {63815E01-AD47-4D83-98F5-87160A503D02}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {63815E01-AD47-4D83-98F5-87160A503D02}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {54D4D857-F008-4817-BFC5-0F3234FF8781}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {54D4D857-F008-4817-BFC5-0F3234FF8781}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {54D4D857-F008-4817-BFC5-0F3234FF8781}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {54D4D857-F008-4817-BFC5-0F3234FF8781}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # The 'SOR' #LunchBox project 2 | 3 | __[Every information is now available on the project's wiki](https://github.com/Lunch-box/SimpleOrderRouting/wiki)__ 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /images/10kfeet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/10kfeet.jpg -------------------------------------------------------------------------------- /images/25kfeet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/25kfeet.jpg -------------------------------------------------------------------------------- /images/5feet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/5feet.jpg -------------------------------------------------------------------------------- /images/Hegagonal-firstDraft.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/Hegagonal-firstDraft.jpg -------------------------------------------------------------------------------- /images/HexaMendel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/HexaMendel.jpg -------------------------------------------------------------------------------- /images/HexaThomas.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/HexaThomas.jpg -------------------------------------------------------------------------------- /images/HexaTomasz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/HexaTomasz.jpg -------------------------------------------------------------------------------- /images/MarketsRaceConditions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/MarketsRaceConditions.jpg -------------------------------------------------------------------------------- /images/PortAndAdapters.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/PortAndAdapters.jpg -------------------------------------------------------------------------------- /images/SOR-bigPicture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/SOR-bigPicture.jpg -------------------------------------------------------------------------------- /images/XPDesign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/XPDesign.jpg -------------------------------------------------------------------------------- /images/You-Are-Here.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/You-Are-Here.jpg -------------------------------------------------------------------------------- /images/duty_calls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/duty_calls.png -------------------------------------------------------------------------------- /images/goodmanpistoff.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunch-box/SimpleOrderRouting/96abee8fb4e9faf0d1e0a35bc39f5e135092290b/images/goodmanpistoff.jpg --------------------------------------------------------------------------------