Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Bots/DennisBot/DennisMoneyBot.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>..\..\Build\Bots</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>..\..\Build\Bots</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="NasdaqTrader.Bot.Core">
<HintPath>..\..\Build\NasdaqTrader.Bot.Core.dll</HintPath>
</Reference>
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions Bots/DennisBot/DennisMoneyBot.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36221.1 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DennisMoneyBot", "DennisMoneyBot.csproj", "{D477DB95-F8AC-0D1D-C1CF-1B7D73E0C2BA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D477DB95-F8AC-0D1D-C1CF-1B7D73E0C2BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D477DB95-F8AC-0D1D-C1CF-1B7D73E0C2BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D477DB95-F8AC-0D1D-C1CF-1B7D73E0C2BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D477DB95-F8AC-0D1D-C1CF-1B7D73E0C2BA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CC4A2F4E-7123-498D-83E9-1206EC1B00EF}
EndGlobalSection
EndGlobal
7 changes: 7 additions & 0 deletions Bots/DennisBot/ITrader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using NasdaqTrader.Bot.Core;

namespace DennisMoneyBot;
internal interface ITrader
{
void DoTrades(ITraderSystemContext systemContext, ITraderBot bot);
}
18 changes: 18 additions & 0 deletions Bots/DennisBot/MoneyBot.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using DennisMoneyBot.Traders;

using NasdaqTrader.Bot.Core;

namespace DennisMoneyBot;

public class MoneyBot : ITraderBot
{
public string CompanyName => "Dennis Makes It Rain";

//ITrader _selectedTrader = new DayTrader();
ITrader _selectedTrader = new ExperimentalTrader();

public async Task DoTurn(ITraderSystemContext systemContext)
{
_selectedTrader.DoTrades(systemContext, this);
}
}
87 changes: 87 additions & 0 deletions Bots/DennisBot/StolenDateExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
namespace DennisMoneyBot;
internal static class StolenDateExtensions
{
/// <summary>
/// Determines if this date is a federal holiday.
/// </summary>
/// <param name="date">This date</param>
/// <returns>True if this date is a federal holiday</returns>
public static bool IsFederalHoliday(this DateOnly date)
{
// to ease typing
int nthWeekDay = (int)(Math.Ceiling((double)date.Day / 7.0d));
DayOfWeek dayName = date.DayOfWeek;
bool isThursday = dayName == DayOfWeek.Thursday;
bool isFriday = dayName == DayOfWeek.Friday;
bool isMonday = dayName == DayOfWeek.Monday;
bool isWeekend = dayName == DayOfWeek.Saturday || dayName == DayOfWeek.Sunday;


//Junteeth
if (new DateOnly(date.Year, 6, 19) == date) return true;
//good friday
if (DateOnly.FromDateTime(EasterSunday(date.Year)).AddDays(-2) == date) return true;

// New Years Day (Jan 1, or preceding Friday/following Monday if weekend)
if ((date.Month == 12 && date.Day == 31 && isFriday) ||
(date.Month == 1 && date.Day == 1 && !isWeekend) ||
(date.Month == 1 && date.Day == 2 && isMonday)) return true;

// MLK day (3rd monday in January)
if (date.Month == 1 && isMonday && nthWeekDay == 3) return true;

// President’s Day (3rd Monday in February)
if (date.Month == 2 && isMonday && nthWeekDay == 3) return true;

// Memorial Day (Last Monday in May)
if (date.Month == 5 && isMonday && date.AddDays(7).Month == 6) return true;

// Independence Day (July 4, or preceding Friday/following Monday if weekend)
if ((date.Month == 7 && date.Day == 3 && isFriday) ||
(date.Month == 7 && date.Day == 4 && !isWeekend) ||
(date.Month == 7 && date.Day == 5 && isMonday)) return true;

// Labor Day (1st Monday in September)
if (date.Month == 9 && isMonday && nthWeekDay == 1) return true;

// Columbus Day (2nd Monday in October)
if (date.Month == 10 && isMonday && nthWeekDay == 2) return true;

// Veteran’s Day (November 11, or preceding Friday/following Monday if weekend))
if ((date.Month == 11 && date.Day == 10 && isFriday) ||
(date.Month == 11 && date.Day == 11 && !isWeekend) ||
(date.Month == 11 && date.Day == 12 && isMonday)) return true;

// Thanksgiving Day (4th Thursday in November)
if (date.Month == 11 && isThursday && nthWeekDay == 4) return true;

// Christmas Day (December 25, or preceding Friday/following Monday if weekend))
if ((date.Month == 12 && date.Day == 24 && isFriday) ||
(date.Month == 12 && date.Day == 25 && !isWeekend) ||
(date.Month == 12 && date.Day == 26 && isMonday)) return true;

return false;
}

public static DateTime EasterSunday(int year)
{
int day = 0;
int month = 0;

int g = year % 19;
int c = year / 100;
int h = (c - (int)(c / 4) - (int)((8 * c + 13) / 25) + 19 * g + 15) % 30;
int i = h - (int)(h / 28) * (1 - (int)(h / 28) * (int)(29 / (h + 1)) * (int)((21 - g) / 11));

day = i - ((year + (int)(year / 4) + i + 2 - c + (int)(c / 4)) % 7) + 28;
month = 3;

if (day > 31)
{
month++;
day -= 31;
}

return new DateTime(year, month, day);
}
}
45 changes: 45 additions & 0 deletions Bots/DennisBot/Traders/DayTrader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using DennisMoneyBot.Utility;

using NasdaqTrader.Bot.Core;

namespace DennisMoneyBot.Traders;
internal class DayTrader : ITrader
{
public void DoTrades(ITraderSystemContext systemContext, ITraderBot bot)
{
var today = systemContext.CurrentDate;
var nextTradingDay = DateCalculator.GetNextValidDate(today);
var currentHoldings = systemContext.GetHoldings(bot);

foreach (var holding in currentHoldings)
{
systemContext.SellStock(bot, holding.Listing, holding.Amount);
}

if (nextTradingDay.Year != today.Year)
{
return;
}

var bestOneDayTrades = systemContext.GetListings()
.OrderByDescending(listing =>
listing.PricePoints.FirstOrDefault(p => p.Date == nextTradingDay)?.Price - listing.PricePoints.FirstOrDefault(p => p.Date == today)?.Price);

int tradesLeft = 2;
foreach (var listing in bestOneDayTrades)
{
int amountToBuy = (int)Math.Min(1000, Math.Floor(systemContext.GetCurrentCash(bot) / listing.PricePoints.First(p => p.Date == today).Price));
if (amountToBuy == 0)
{
continue;
}

systemContext.BuyStock(bot, listing, amountToBuy);

if (--tradesLeft < 1)
{
break;
}
}
}
}
52 changes: 52 additions & 0 deletions Bots/DennisBot/Traders/ExperimentalTrader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using DennisMoneyBot.Utility;

using NasdaqTrader.Bot.Core;

namespace DennisMoneyBot.Traders;
internal class ExperimentalTrader : ITrader
{
public void DoTrades(ITraderSystemContext systemContext, ITraderBot bot)
{
int windowSize = 1;
decimal saleCutoffRatio = 1.15M;
int daysToIgnoreSaleRules = 14;
int minimalSaleValue = 800;

var today = systemContext.CurrentDate;
var nextTradingDay = DateCalculator.GetBusinessDaysInTheFuture(today, windowSize);
IHolding[]? currentHoldings = systemContext.GetHoldings(bot);

foreach (var holding in currentHoldings)
{
if ((PriceCalculator.GetValueOfHoldingOnDate(holding, today) > minimalSaleValue)
&&
(PriceCalculator.GetPricePointRatio(holding.Listing, today, nextTradingDay) < saleCutoffRatio
|| (systemContext.StartDate.AddDays(daysToIgnoreSaleRules) > systemContext.CurrentDate)))
{
systemContext.SellStock(bot, holding.Listing, holding.Amount);
}
}

var bestOneDayTrades = systemContext.GetListings()
.OrderByDescending(listing =>
PriceCalculator.CalculateProfitMargin(systemContext, bot, listing, today, nextTradingDay));

int tradesLeft = systemContext.GetTradesLeftForToday(bot);
foreach (var listing in bestOneDayTrades)
{
int amountToBuy = (int)Math.Min(1000, Math.Floor(systemContext.GetCurrentCash(bot) / PriceCalculator.GetPriceForListingOnDate(listing, today)));
if (amountToBuy == 0)
{
continue;
}

systemContext.BuyStock(bot, listing, amountToBuy);

if (--tradesLeft < 1)
{
break;
}
}
// nog iets doen met voorrang geven aan dingen die gewoon veel waard zijn en niet meer gaan dalen, zodat dat kan accumuleren
}
}
23 changes: 23 additions & 0 deletions Bots/DennisBot/Utility/DateCalculator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace DennisMoneyBot.Utility;
internal static class DateCalculator
{
public static DateOnly GetNextValidDate(DateOnly currentDate)
{
DateOnly nextDate = currentDate.AddDays(1);
while (nextDate.DayOfWeek == DayOfWeek.Saturday || nextDate.DayOfWeek == DayOfWeek.Sunday || nextDate.IsFederalHoliday())
{
nextDate = nextDate.AddDays(1);
}
return nextDate;
}

public static DateOnly GetBusinessDaysInTheFuture(DateOnly currentDate, int amountOfDays)
{
var nextDay = currentDate;
for (int i = 0; i < amountOfDays; i++)
{
nextDay = GetNextValidDate(nextDay);
}
return nextDay;
}
}
33 changes: 33 additions & 0 deletions Bots/DennisBot/Utility/PriceCalculator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using NasdaqTrader.Bot.Core;

namespace DennisMoneyBot.Utility;
internal static class PriceCalculator
{
public static decimal GetPriceForListingOnDate(IStockListing listing, DateOnly referenceDate)
{
return listing.PricePoints.FirstOrDefault(p => p.Date == referenceDate)?.Price ?? 0;
}

public static decimal GetPricePointRatio(IStockListing listing, DateOnly today, DateOnly nextReferenceDay)
{
return GetPriceForListingOnDate(listing, nextReferenceDay) / GetPriceForListingOnDate(listing, today);
}

public static decimal GetValueOfHoldingOnDate(IHolding holding, DateOnly referenceDate)
{
return holding.Amount * GetPriceForListingOnDate(holding.Listing, referenceDate);
}

public static decimal CalculateProfitMargin(ITraderSystemContext systemContext, ITraderBot bot, IStockListing listing, DateOnly today, DateOnly nextReferenceDay)
{
var nextPrice = GetPriceForListingOnDate(listing, nextReferenceDay);
var currentPrice = GetPriceForListingOnDate(listing, today);
var priceDifference = nextPrice - currentPrice;

var amountToBuy =
currentPrice == 0
? 0
: Math.Min(1000, Math.Floor(systemContext.GetCurrentCash(bot) / currentPrice));
return amountToBuy * priceDifference;
}
}
Loading