예제 #1
0
        public async Task GetPriceEstimation(PriceEstimationInputModel inputModel)
        {
            const double AdditionalAreaFactor = 0.3; //Additional area is worth 30% as much as the main area

            // Get Sold objects in area
            var previouslySoldObjectsInArea = await _booliPriceEstimatorRepository.GetSoldObjectsInArea(inputModel.AreaName);

            // Filter
            previouslySoldObjectsInArea = previouslySoldObjectsInArea.Where(l => l.LivingArea > 0 && l.SoldPrice > 0).ToList();

            var estimationModels = previouslySoldObjectsInArea.Select(_ => new PriceEstimationModel(_)).ToList();

            //var adjustedSquareMeterPrice = GetSquareMeterPriceBasedOnRent(estimationModels, inputModel);

            var adjustedSquareMeterPrice = GetSquareMeterPriceBasedOnLocation(estimationModels, inputModel);

            // Is it close to water?

            // Is it a new building?

            // Is it high up?

            // What direction is the price heading/ trending? Can we get a 1st or 2nd degree coefficient? By only focusing on last 2Q we can ignore this....

            // How many objects have been sold?

            var priceEstimate = adjustedSquareMeterPrice * inputModel.Size;

            if (inputModel.AdditionalArea != 0)
            {
                priceEstimate += (int)Math.Round(inputModel.AdditionalArea * AdditionalAreaFactor);
            }


            Console.WriteLine($"A apartment in {inputModel.AreaName} that is {inputModel.Size} square meters large and with a rent of {inputModel.Rent} SEK/ month is estimated to: ");
            Console.WriteLine(string.Format("{0:#,0}", priceEstimate) + " SEK");
            Console.ReadLine();
        }
예제 #2
0
        static void Main(string[] args)
        {
            // configure services
            var services = new ServiceCollection()
                           .AddTransient <IBooliPriceEstimatorRepository, BooliPriceEstimatorRepository>()
                           .AddTransient <IBooliApiHandler, BooliApiHandler>()
                           .AddTransient <IBooliPriceEstimator, BooliPriceEstimator>()
                           .AddDbContext <BooliPriceEstimatorContext>(_ => _.UseSqlServer(@"Server=localhost;Database=Booli.Kodprov;Trusted_Connection=True;ConnectRetryCount=0"));

            // create a service provider from the service collection
            var serviceProvider = services.BuildServiceProvider();

            // resolve the dependency graph
            //var booliApiHandler = serviceProvider.GetService<IBooliApiHandler>();
            //booliApiHandler.SyncSoldObjectsItteratively().Wait();

            var booliPriceEstimator = serviceProvider.GetService <IBooliPriceEstimator>();

            //booliApiHandler.SyncSoldObjectsItteratively().Wait();
            var estimationInputModel = new PriceEstimationInputModel(74, "Årsta", 5000, StreetNameExamples.Siljansvagen72);

            booliPriceEstimator.GetPriceEstimation(estimationInputModel).Wait();
        }
예제 #3
0
        private int GetSquareMeterPriceBasedOnLocation(List <PriceEstimationModel> estimationModels, PriceEstimationInputModel inputModel)
        {
            const int ThresholdNrOfObjects = 10;
            const int SearchDistanceKm     = 1;

            // Maybe do these two itteratively until we find a good number of candidates?
            //1.
            var now          = DateTime.Now;
            var recentlySold = estimationModels.Where(em => (now - em.SoldDate.SoldDateTime).Days < 365).ToList();

            if (recentlySold.Count < ThresholdNrOfObjects)
            {
                throw new Exception($"{recentlySold.Count}, too few sold objects found in the area dating a year back!");
            }

            //2.
            var recentlySoldNearObjectOfInterest = recentlySold.Where(rs => (double)Calculations.PositionsToMetersDistance(rs.Position, inputModel.Position) / 1000.0 < SearchDistanceKm).ToList();

            if (recentlySoldNearObjectOfInterest.Count < ThresholdNrOfObjects)
            {
                throw new Exception($"{recentlySoldNearObjectOfInterest.Count}, too few sold objects in within a {SearchDistanceKm} km radius found!");
            }

            SetRentRange(recentlySoldNearObjectOfInterest, inputModel);
            var rentFactor = GetRentFactor(inputModel.RentRange);

            var medianSquareMeterPrice = GetMedianSquareMeterPrice(recentlySoldNearObjectOfInterest);

            return((int)(medianSquareMeterPrice * rentFactor));
            //return (int)(medianSquareMeterPrice ); //I found it more accurate if I removed rent factor
        }
예제 #4
0
        private PriceEstimationModel GetSoldObjectWithSimilarRent(List <PriceEstimationModel> last2QSoldObjects, PriceEstimationInputModel inputModel)
        {
            var soldModelsOrderedByRent = last2QSoldObjects.OrderBy(_ => _.Rent).ToList();

            var previousSoldModel = soldModelsOrderedByRent[0];

            for (int i = 1; i < soldModelsOrderedByRent.Count; i++)
            {
                var currentSoldModel = soldModelsOrderedByRent[i];
                if (currentSoldModel.Rent > inputModel.Rent)
                {
                    var nearestSoldModelByRent = GetNearestSoldModel(previousSoldModel, currentSoldModel, inputModel.Rent);
                    return(nearestSoldModelByRent);
                }
            }

            return(soldModelsOrderedByRent.Last());
        }
예제 #5
0
        //private int GetRecentlySoldObjects(List<PriceEstimationModel> estimationModels)
        //{
        //    var now = DateTime.Now;
        //    var recentlySold = estimationModels.Where(em => (now - em.SoldDate.SoldDateTime).Days < 365).ToList();
        //    return recentlySold;
        //}

        private int GetSquareMeterPriceBasedOnRent(List <PriceEstimationModel> estimationModels, PriceEstimationInputModel inputModel)
        {
            const int thresholdNrOfObjects = 10;

            //Get mean for the last 2 quarters.
            var last2QSoldObjects = GetPreviousTwoQuartersSoldData(estimationModels);

            if (last2QSoldObjects.Count < thresholdNrOfObjects)
            {
                //do something cool
            }

            //Calculations.CoordinatesToMeters

            // Is the rent high for the area?
            //var lowestNonZeroRentModel = last2QSoldObjects.Where(_ => _.Rent != 0).OrderBy(_ => _.Rent).First();
            //var highestNonZeroRentModel = last2QSoldObjects.Where(_ => _.Rent != 0).OrderByDescending(_ => _.Rent).First();

            // Where on the scale is the subject?
            var mostSimilarRentSubject = GetSoldObjectWithSimilarRent(last2QSoldObjects, inputModel);

            var baseRent = mostSimilarRentSubject.Rent;

            return((int)baseRent);
        }
예제 #6
0
        private void SetRentRange(List <PriceEstimationModel> recentlySoldNearObjectOfInterest, PriceEstimationInputModel inputModel)
        {
            const double RentPercentageDiffThreshold = 0.2;// +- 20% threshold of median rent

            var medianRentPrice = GetMedianRentPrice(recentlySoldNearObjectOfInterest);

            //var maxVariation = GetLowestRent

            // 2. Figure out if inputModel is +- 20% of median
            var rentDiff = (double)inputModel.Rent / (double)medianRentPrice;

            // rent diff is less than 80% of median
            if (rentDiff < (1 - RentPercentageDiffThreshold)) //20% less than median
            {
                inputModel.RentRange = RentRange.Below;
            }

            // rent diff is more than 120% of median
            else if (rentDiff > (1 + RentPercentageDiffThreshold)) //20% less than median
            {
                inputModel.RentRange = RentRange.Above;
            }

            else
            {
                inputModel.RentRange = RentRange.Average;
            }
        }